Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/authentication #183

Open
wants to merge 86 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 82 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
8daf59a
#SOS-15
Jackafive753 May 28, 2021
35a3f71
#SOS-22
Jackafive753 May 29, 2021
5866b6e
#SOS-15
Jackafive753 May 31, 2021
839ae2f
#SOS-23 Add getAccounts + save account information in event_status
daniebrill Jun 4, 2021
6cd0a85
#SOS-23 Use querylimit in aggregation + add error handling for type a…
daniebrill Jun 5, 2021
f8e931b
#SOS-23 Fix existing tests + code format
daniebrill Jun 8, 2021
259ccf7
#SOS-23 Modify GetAccounts for specific execution ID
daniebrill Jun 8, 2021
45db9b4
#SOS-23 Fit MockStorage to modified interface StorageDescriber
daniebrill Jun 8, 2021
2f3c15c
#SOS-23 Add tests in interpolation_test.go and server_test.go
daniebrill Jun 8, 2021
1fd641a
#SOS-20
Jackafive753 Jun 9, 2021
9c157f2
#SOS-23 Add test for elasticsearch GetAccounts
daniebrill Jun 9, 2021
0f68ad2
#SOS-16
Jackafive753 Jun 10, 2021
2b48f30
Merge remote-tracking branch 'origin/feature_multi_account_selection'…
Jackafive753 Jun 10, 2021
bf4c57d
#SOS18 Add multiaccount selection functionality to tables
daniebrill Jun 11, 2021
ecbe7ef
#SOS-16
Jackafive753 Jun 11, 2021
5a7065e
Merge remote-tracking branch 'origin/feature_multi_account_selection'…
Jackafive753 Jun 11, 2021
5ea12e5
#SOS-18
Jackafive753 Jun 14, 2021
2f99548
#SOS-18
daniebrill Jun 14, 2021
2c3e562
Merge pull request #1 from evoila/feature_multi_account_selection
Jackafive753 Jun 16, 2021
8416b89
#SOS-31
florianbieser Jun 16, 2021
e55138e
#SOS-26
daniebrill Jun 16, 2021
454eb3a
#SOS-25
Jackafive753 Jun 17, 2021
1165abe
#SOS-25
Jackafive753 Jun 21, 2021
2effc76
#SOS-25
Jackafive753 Jun 21, 2021
99ad636
#SOS-25
Jackafive753 Jun 21, 2021
12893e8
#SOS-25
Jackafive753 Jun 21, 2021
5b7187c
Changed some things to test -> Delete if somehting breaks
Jun 22, 2021
b95df02
Fix ESLint Errors
Jackafive753 Jun 22, 2021
9429c6f
I dont care
Jun 25, 2021
49ec1ad
Merge remote-tracking branch 'origin/Testing_CSV' into Testing_CSV
Jun 25, 2021
bcc2b72
I cant care less
Jun 25, 2021
47e3a84
Fix csvDownload functionality
Jackafive753 Jun 25, 2021
6f82820
#SOS-33
Jackafive753 Jun 28, 2021
580c0fc
CSVDownloadButton now only shows up in 'Summary' ResourceChart to avo…
Jun 28, 2021
6f24513
Merge remote-tracking branch 'origin/Testing_CSV' into feature_all_su…
Jun 28, 2021
e0a87bd
Removed exactly one whitespace
Jun 29, 2021
eeebb64
Added exactly one whitespace
Jun 29, 2021
f380430
Removed absolutely nothing
Jun 30, 2021
6ee0db8
bugfix: Kinesis priceList error
Jackafive753 Jun 30, 2021
c6b916e
bugfix: kinesis priceList Error
Jackafive753 Jun 30, 2021
9242b0a
bugfix: kinesis priceList error
Jackafive753 Jun 30, 2021
0912705
Testing
Jul 1, 2021
032c425
Reverted
Jul 1, 2021
b0db552
Merge branch 'feature_all_summary_report' into Presentation
Jul 1, 2021
0a3d235
Lint Error Fixes
Jul 1, 2021
db579e7
bugfix: kinesis priceList error
Jackafive753 Jul 1, 2021
604e28a
bugfix: kinesis priceList Error
Jackafive753 Jul 1, 2021
98ec140
Add material ui button for CSV report
daniebrill Jul 1, 2021
f368f66
Merge pull request #3 from evoila/bugfix/priceListError
Jackafive753 Jul 1, 2021
056f76e
Merge pull request #2 from evoila/feature_add_S3
DerOtt Jul 1, 2021
277cf89
#SOS-29
florianbieser Jul 1, 2021
4df494c
fix warnings: unused statements
Jackafive753 Jul 2, 2021
8e464cf
fix warnings: unused statements
Jackafive753 Jul 2, 2021
c4876ef
Testing
Jul 6, 2021
0240d59
Merge remote-tracking branch 'origin/feature_add_ECS' into feature_ad…
Jul 6, 2021
67c7481
Fixed a small bug
Jul 7, 2021
dc5abf0
Added more funcs lol. Price might be added
Jul 7, 2021
f8677e8
Add account section for authentication to api.yaml + extend api confi…
daniebrill Jul 9, 2021
1161a8b
Did more things
Jul 10, 2021
18d6bb9
# SOS-30
Jackafive753 Jul 10, 2021
e88c686
Cleanup and more
Jul 10, 2021
1c2ef4b
Removed some comments
Jul 12, 2021
d9b9549
# SOS-48
Jackafive753 Jul 14, 2021
3919a61
# SOS-48
Jackafive753 Jul 14, 2021
0f438d4
token expire time from 5 minute to 1 hour
Jackafive753 Jul 14, 2021
8652ce0
Merge branch 'master' into feature_add_EKS
Jackafive753 Jul 15, 2021
c0b22ea
Merge pull request #4 from evoila/feature_add_EKS
Jackafive753 Jul 15, 2021
c8f8594
Merge pull request #5 from evoila/feature_add_ECS
Jackafive753 Jul 15, 2021
c37b051
Merge pull request #6 from evoila/feature_all_summary_report
Jackafive753 Jul 15, 2021
747ebba
Merge branch 'Presentation' into master
Jackafive753 Jul 15, 2021
b398f03
Merge pull request #7 from evoila/master
Jackafive753 Jul 15, 2021
e7be2b2
Merge branch 'Presentation' into feature/authentication
Jackafive753 Jul 15, 2021
7c31628
add authentication with cookie
Jackafive753 Jul 19, 2021
7071ebd
add authentication throttle
Jackafive753 Jul 19, 2021
c01bbd0
Add authentication request + initial call in DataFactory.js
daniebrill Jul 23, 2021
ab6405e
# SOS-57
Jackafive753 Jul 23, 2021
13c945a
Experimental first version of login.js
Jul 26, 2021
3864503
Adjust api for cookie requests
daniebrill Jul 27, 2021
0321b8d
change token library
Jackafive753 Jul 27, 2021
aace352
Add UI Authentication functionality
daniebrill Jul 27, 2021
81fe9fc
Replace unmaintained auth library in api server test files
daniebrill Jul 27, 2021
f8adc70
set account to filters if an account specific Chart is clicked
Jackafive753 Jul 28, 2021
16da0d8
Show error message for wrong credentials + login with enter
daniebrill Jul 28, 2021
a3fdc4f
authentication needed for report
Jackafive753 Jul 28, 2021
21302ae
position test method
Jackafive753 Jul 28, 2021
6f1fd26
Merge pull request #6 from daniebrill/feature/multi_account_selection
daniebrill Aug 2, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions api/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,26 @@ type StorageConfig struct {
ElasticSearch ElasticsearchConfig `yaml:"elasticsearch"`
}

type AccountConfig struct {
Name string `yaml:"name"`
Password string `yaml:"password"`
}

type AuthenticationConfig struct {
Enabled bool `yaml:"enabled"`
Accounts []AccountConfig `yaml:"accounts"`
}

type UIServerConfig struct {
Address string `yaml:"address"`
}

// APIConfig present the application config
type APIConfig struct {
LogLevel string `yaml:"log_level"`
Storage StorageConfig `yaml:"storage"`
LogLevel string `yaml:"log_level"`
UIServer UIServerConfig `yaml:"ui_server"`
Storage StorageConfig `yaml:"storage"`
Authentication AuthenticationConfig `yaml:"authentication"`
}

// LoadAPI will load yaml file go struct
Expand All @@ -49,6 +65,5 @@ func LoadAPI(location string) (APIConfig, error) {
}).Info("override storage endpoint")
config.Storage.ElasticSearch.Endpoints = strings.Split(overrideStorageEndpoint, ",")
}

return config, nil
}
10 changes: 8 additions & 2 deletions api/config/testutil/mock/config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
---
log_level: info

ui_server:
address: http://127.0.0.1:8080
storage:
elasticsearch:
index: general
username: ""
password: ""
endpoints:
- http://127.0.0.1:9200
- http://127.0.0.1:9200
authentication:
enabled: true
accounts:
- name: User
password: Password
212 changes: 212 additions & 0 deletions api/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/json"
"finala/api/httpparameters"
"finala/api/storage"
"fmt"
"github.com/golang-jwt/jwt"
"io/ioutil"
"net/http"
"net/url"
Expand Down Expand Up @@ -55,6 +57,20 @@ func (server *Server) GetExecutions(resp http.ResponseWriter, req *http.Request)
server.JSONWrite(resp, http.StatusOK, results)
}

func (server *Server) GetAccounts(resp http.ResponseWriter, req *http.Request) {
queryLimit, _ := strconv.Atoi(httpparameters.QueryParamWithDefault(req, "querylimit", storage.GetExecutionsQueryLimit))
params := mux.Vars(req)
executionID := params["executionID"]
accounts, err := server.storage.GetAccounts(executionID, queryLimit)

if err != nil {
server.JSONWrite(resp, http.StatusInternalServerError, HttpErrorResponse{Error: err.Error()})
return

}
server.JSONWrite(resp, http.StatusOK, accounts)
}

// GetResourceData return resuts details by resource type
func (server *Server) GetResourceData(resp http.ResponseWriter, req *http.Request) {
queryParams := req.URL.Query()
Expand Down Expand Up @@ -167,6 +183,79 @@ func (server *Server) DetectEvents(resp http.ResponseWriter, req *http.Request)

}

func (server *Server) Login(resp http.ResponseWriter, req *http.Request) {
if req.Method == http.MethodOptions {
server.JSONWrite(resp, http.StatusOK, nil)
return
}
if server.authentication.Enabled {
buf, bodyErr := ioutil.ReadAll(req.Body)

if bodyErr != nil {
server.JSONWrite(resp, http.StatusBadRequest, HttpErrorResponse{Error: bodyErr.Error()})
return
}

var detectUser map[string]string
err := json.Unmarshal(buf, &detectUser)
if err != nil {
server.JSONWrite(resp, http.StatusBadRequest, HttpErrorResponse{Error: err.Error()})
return
}

for _, user := range server.authentication.Accounts {
if detectUser["Username"] == user.Name && detectUser["Password"] == user.Password {

expTime := time.Now().Add(time.Hour * 1)

atClaims := jwt.MapClaims{}
atClaims["authorized"] = true
atClaims["user_id"] = user.Name
atClaims["exp"] = expTime.Unix()
at := jwt.NewWithClaims(jwt.SigningMethodHS256, atClaims)
token, err := at.SignedString([]byte("secret"))
if err != nil {
server.JSONWrite(resp, http.StatusInternalServerError, HttpErrorResponse{Error: err.Error()})
return
}

cookie := http.Cookie{
Name: "jwt",
Value: token,
Expires: expTime,
SameSite: http.SameSiteLaxMode,
}

http.SetCookie(resp, &cookie)
return
}
}
server.JSONWrite(resp, http.StatusUnauthorized, "{\"message\":\"Login data not authorized\"}")
} else {
expTime := time.Now().Add(time.Hour * 1)

atClaims := jwt.MapClaims{}
atClaims["authorized"] = true
atClaims["user_id"] = "user"
atClaims["exp"] = expTime.Unix()
at := jwt.NewWithClaims(jwt.SigningMethodHS256, atClaims)
token, err := at.SignedString([]byte("secret"))
if err != nil {
server.JSONWrite(resp, http.StatusInternalServerError, HttpErrorResponse{Error: err.Error()})
return
}

cookie := http.Cookie{
Name: "jwt",
Value: token,
Expires: expTime,
SameSite: http.SameSiteLaxMode,
}

http.SetCookie(resp, &cookie)
}
}

//NotFoundRoute return when route not found
func (server *Server) NotFoundRoute(resp http.ResponseWriter, req *http.Request) {
server.JSONWrite(resp, http.StatusNotFound, HttpErrorResponse{Error: "Path not found"})
Expand All @@ -186,3 +275,126 @@ func (server *Server) VersionHandler(resp http.ResponseWriter, req *http.Request
}
server.JSONWrite(resp, http.StatusOK, version)
}

func (server *Server) middleware(next http.Handler) http.HandlerFunc {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
cookie, err := req.Cookie("jwt")

if err != nil {
server.JSONWrite(resp, http.StatusUnauthorized, HttpErrorResponse{Error: "Authorize cookie not found"})
return
}
claims := jwt.MapClaims{}
_, err = jwt.ParseWithClaims(cookie.Value, claims, func(token *jwt.Token) (interface{}, error) {
return []byte("secret"), nil
})

if err != nil {
server.JSONWrite(resp, http.StatusUnauthorized, HttpErrorResponse{Error: err.Error()})
return
}

next.ServeHTTP(resp, req)
})
}

//Returns json thingy wingy dingy i dont know how
func (server *Server) GetReport(resp http.ResponseWriter, req *http.Request) {
queryParams := req.URL.Query()
params := mux.Vars(req)
executionID := params["executionID"]
filters := httpparameters.GetFilterQueryParamWithOutPrefix(queryParamFilterPrefix, queryParams)

log.WithFields(log.Fields{
"filter": filters,
}).Info("filter")

filterForSummary := make(map[string]string)
for filterKey, filterValue := range filters {
filterForSummary[filterKey] = filterValue
}

response, err := server.storage.GetSummary(executionID, filterForSummary)
if err != nil {
server.JSONWrite(resp, http.StatusInternalServerError, HttpErrorResponse{Error: err.Error()})
return

}

var result []map[string]interface{}
var attributeList []string

for resourceName, resourceSummary := range response {
fmt.Println(resourceName, resourceSummary) //sanity test
if resourceSummary.ResourceCount > 0 {
resourcesList, err := server.storage.GetResources(resourceName, executionID, filters)
if err != nil {
server.JSONWrite(resp, http.StatusInternalServerError, HttpErrorResponse{Error: err.Error()})
continue
}

log.WithFields(log.Fields{
"name": resourceName,
"executionID": executionID,
"filter": filters,
}).Info(resourcesList)

//can still fail for some odd reason so we check if the resource is actually there
if resourcesList[0] == nil {
server.JSONWrite(resp, http.StatusInternalServerError, HttpErrorResponse{Error: err.Error()})
return
}
data, ok := resourcesList[0]["Data"].(map[string]interface{})
if !ok {
//screw your log
continue
}
for key := range data {
if key == "Tag" {
continue
}
exists := false
for index := range attributeList {
if attributeList[index] == key {
exists = true
}
}
if !exists {
attributeList = append(attributeList, key)
}
}

}
}

for resourceName, resourceSummary := range response {
fmt.Println(resourceName, resourceSummary) //sanity test
if resourceSummary.ResourceCount > 0 {
resourcesList, err := server.storage.GetResources(resourceName, executionID, filters)
if err != nil {
server.JSONWrite(resp, http.StatusInternalServerError, HttpErrorResponse{Error: err.Error()})
continue
}
for _, element := range resourcesList {
data, ok := element["Data"].(map[string]interface{})
if !ok {
//screw your log
continue
}

delete(data, "Tag")

for _, attrName := range attributeList {
_, ok := data[attrName]
if !ok {
data[attrName] = nil
}
}
result = append(result, data)
}

}
}

server.JSONWrite(resp, http.StatusOK, result)
}
40 changes: 25 additions & 15 deletions api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"context"
"encoding/json"
"finala/api/config"
"fmt"
"net/http"
"time"
Expand All @@ -24,23 +25,29 @@ const (

// Server is the API server struct
type Server struct {
router *mux.Router
httpserver *http.Server
storage storage.StorageDescriber
version version.VersionManagerDescriptor
router *mux.Router
httpserver *http.Server
storage storage.StorageDescriber
authentication config.AuthenticationConfig
version version.VersionManagerDescriptor
}

// NewServer returns a new Server
func NewServer(port int, storage storage.StorageDescriber, version version.VersionManagerDescriptor) *Server {
func NewServer(port int, storage storage.StorageDescriber, version version.VersionManagerDescriptor, auth config.AuthenticationConfig, allowedOrigin string) *Server {

router := mux.NewRouter()
corsObj := handlers.AllowedOrigins([]string{"*"})
corsObjects := []handlers.CORSOption{}
corsObjects = append(corsObjects, handlers.AllowedOrigins([]string{allowedOrigin}))
corsObjects = append(corsObjects, handlers.AllowedMethods([]string{"GET", "POST", "OPTIONS"}))
corsObjects = append(corsObjects, handlers.AllowedHeaders([]string{"Content-Type"}))
corsObjects = append(corsObjects, handlers.AllowCredentials())
return &Server{
router: router,
storage: storage,
version: version,
router: router,
storage: storage,
version: version,
authentication: auth,
httpserver: &http.Server{
Handler: handlers.CORS(corsObj)(router),
Handler: handlers.CORS(corsObjects...)(router),
Addr: fmt.Sprintf("0.0.0.0:%d", port),
},
}
Expand Down Expand Up @@ -79,12 +86,15 @@ func (server *Server) Serve() serverutil.StopFunc {
// BindEndpoints sets up the router to handle API endpoints
func (server *Server) BindEndpoints() {

server.router.HandleFunc("/api/v1/summary/{executionID}", server.GetSummary).Methods("GET")
server.router.HandleFunc("/api/v1/executions", server.GetExecutions).Methods("GET")
server.router.HandleFunc("/api/v1/resources/{type}", server.GetResourceData).Methods("GET")
server.router.HandleFunc("/api/v1/trends/{type}", server.GetResourceTrends).Methods("GET")
server.router.HandleFunc("/api/v1/tags/{executionID}", server.GetExecutionTags).Methods("GET")
server.router.HandleFunc("/api/v1/summary/{executionID}", server.middleware(http.HandlerFunc(server.GetSummary))).Methods("GET")
server.router.HandleFunc("/api/v1/executions", server.middleware(http.HandlerFunc(server.GetExecutions))).Methods("GET")
server.router.HandleFunc("/api/v1/accounts/{executionID}", server.middleware(http.HandlerFunc(server.GetAccounts))).Methods(("GET"))
server.router.HandleFunc("/api/v1/resources/{type}", server.middleware(http.HandlerFunc(server.GetResourceData))).Methods("GET")
server.router.HandleFunc("/api/v1/trends/{type}", server.middleware(http.HandlerFunc(server.GetResourceTrends))).Methods("GET")
server.router.HandleFunc("/api/v1/tags/{executionID}", server.middleware(http.HandlerFunc(server.GetExecutionTags))).Methods("GET")
server.router.HandleFunc("/api/v1/report/{executionID}", server.middleware(http.HandlerFunc(server.GetReport))).Methods("GET")
server.router.HandleFunc("/api/v1/detect-events/{executionID}", server.DetectEvents).Methods("POST")
server.router.HandleFunc("/api/v1/login", server.Login).Methods("POST", "OPTIONS")
server.router.HandleFunc("/api/v1/version", server.VersionHandler).Methods("GET")
server.router.HandleFunc("/api/v1/health", server.HealthCheckHandler).Methods("GET")
server.router.NotFoundHandler = http.HandlerFunc(server.NotFoundRoute)
Expand Down
Loading