From 49b4849fc285681c3f05588adf364000a4aa3217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Wed, 19 Oct 2016 10:40:32 +0200 Subject: [PATCH 01/18] Added docker-compose.yml --- scripts/docker/docker-compose.yml | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 scripts/docker/docker-compose.yml diff --git a/scripts/docker/docker-compose.yml b/scripts/docker/docker-compose.yml new file mode 100644 index 0000000..3c3e892 --- /dev/null +++ b/scripts/docker/docker-compose.yml @@ -0,0 +1,33 @@ +version: "2" +services: + postgrescompose: + image: "postgres:9.5" + container_name: "postgrescompose" + hostname: "postgrescompose" + ports: + - "5432:5432" + command: "postgres" + foulkonworkercompose: + image: "tecsisa/foulkon:v0.2.0" + container_name: "foulkonworkercompose" + hostname: "foulkonworkercompose" + environment: + - FOULKON_WORKER_HOST=foulkonworkercompose + - FOULKON_WORKER_PORT=8000 + - FOULKON_ADMIN_USER=admin + - FOULKON_ADMIN_PASS=admin + - FOULKON_WORKER_LOG_TYPE=default + - FOULKON_WORKER_LOG_LEVEL=info + - FOULKON_DB=postgres + - FOULKON_DB_POSTGRES_DS=postgres://postgres:password@postgrescompose:5432/postgres?sslmode=disable + - FOULKON_DB_POSTGRES_IDLECONNS=10 + - FOULKON_DB_POSTGRES_MAXCONNS=20 + - FOULKON_DB_POSTGRES_CONNTTL=300 + - FOULKON_AUTH_TYPE=oidc + - FOULKON_AUTH_ISSUER=https://accounts.google.com + - FOULKON_AUTH_CLIENTID=google-client-identity + ports: + - "8000:8000" + command: "worker" + depends_on: + - postgrescompose From 69283ea64d91bd6f5c315ca609b779c2cc7ede12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Fri, 21 Oct 2016 14:17:49 +0200 Subject: [PATCH 02/18] added demo folder --- demo/Dockerfile | 15 ++++ demo/api/main.go | 141 +++++++++++++++++++++++++++++++ demo/docker-compose.yml | 33 ++++++++ demo/web/main.go | 147 +++++++++++++++++++++++++++++++++ demo/web/tmpl/base/footer.html | 3 + demo/web/tmpl/base/header.html | 21 +++++ demo/web/tmpl/index.html | 8 ++ 7 files changed, 368 insertions(+) create mode 100644 demo/Dockerfile create mode 100644 demo/api/main.go create mode 100644 demo/docker-compose.yml create mode 100644 demo/web/main.go create mode 100644 demo/web/tmpl/base/footer.html create mode 100644 demo/web/tmpl/base/header.html create mode 100644 demo/web/tmpl/index.html diff --git a/demo/Dockerfile b/demo/Dockerfile new file mode 100644 index 0000000..e5e1b0f --- /dev/null +++ b/demo/Dockerfile @@ -0,0 +1,15 @@ +FROM alpine +MAINTAINER Tecsisa + +USER root +RUN apk update && apk add ca-certificates + +# API +COPY bin/demoapi /go/bin/demoapi + +# WEB +COPY bin/demoweb /go/bin/demoweb + +ENV PATH=$PATH:/go/bin + +EXPOSE 8000 8001 \ No newline at end of file diff --git a/demo/api/main.go b/demo/api/main.go new file mode 100644 index 0000000..ec9facb --- /dev/null +++ b/demo/api/main.go @@ -0,0 +1,141 @@ +package main + +import ( + "encoding/json" + "github.com/coreos/dex/pkg/log" + "github.com/julienschmidt/httprouter" + "net/http" + "os" +) + +// CONSTANTS +const ( + // Environment Vars + HOST = "APIHOST" + PORT = "APIPORT" + + // HTTP Constants + RESOURCE_ID = "id" +) + +type Resource struct { + Id string `json:"id, omitempty"` + Resource string `json:"resource, omitempty"` +} + +var resources map[string]string + +func HandleAddResource(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + request := &Resource{} + err := processHttpRequest(r, request) + var response *Resource + if err == nil { + resources[request.Id] = request.Resource + response = request + } + processHttpResponse(w, response, err, http.StatusOK) +} + +func HandleGetResource(w http.ResponseWriter, _ *http.Request, ps httprouter.Params) { + var response *Resource + var statusCode int + if val, ok := resources[ps.ByName(RESOURCE_ID)]; ok { + response = &Resource{ + Id: ps.ByName(RESOURCE_ID), + Resource: val, + } + statusCode = http.StatusOK + } else { + statusCode = http.StatusNotFound + } + processHttpResponse(w, response, nil, statusCode) +} + +func HandlePutResource(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + request := &Resource{} + err := processHttpRequest(r, request) + var response *Resource + if err == nil { + resources[request.Id] = request.Resource + response = request + } + processHttpResponse(w, response, err, http.StatusOK) +} + +func HandleDelResource(w http.ResponseWriter, _ *http.Request, ps httprouter.Params) { + var statusCode int + if _, ok := resources[ps.ByName(RESOURCE_ID)]; ok { + delete(resources, ps.ByName(RESOURCE_ID)) + statusCode = http.StatusNoContent + } else { + statusCode = http.StatusNotFound + } + processHttpResponse(w, nil, nil, statusCode) +} + +func HandleListResources(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { + response := make([]Resource, len(resources)) + for key, val := range resources { + response = append(response, Resource{Id: key, Resource: val}) + } + processHttpResponse(w, response, nil, http.StatusOK) +} + +func main() { + + // Create the muxer to handle the actual endpoints + router := httprouter.New() + + router.POST("/resources", HandleAddResource) + router.GET("/resources/:id", HandleGetResource) + router.PUT("/resources/:id", HandlePutResource) + router.DELETE("/resources/:id", HandleDelResource) + router.GET("/resources", HandleListResources) + + // Start server + resources = make(map[string]string) + host := os.Getenv(HOST) + port := os.Getenv(PORT) + log.Fatal(http.ListenAndServe(host+":"+port, router)) + +} + +// Private Helper Methods + +func processHttpRequest(r *http.Request, request interface{}) error { + // Decode request if passed + if request != nil { + err := json.NewDecoder(r.Body).Decode(&request) + if err != nil { + return err + } + } + + return nil +} + +func processHttpResponse(w http.ResponseWriter, response interface{}, err error, responseCode int) { + if err != nil { + http.Error(w, err.Error(), responseCode) + return + } + + var data []byte + if response != nil { + data, err = json.Marshal(response) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + + switch responseCode { + case http.StatusOK: + w.Write(data) + case http.StatusCreated: + w.Write(data) + } + + w.WriteHeader(responseCode) + +} diff --git a/demo/docker-compose.yml b/demo/docker-compose.yml new file mode 100644 index 0000000..3c3e892 --- /dev/null +++ b/demo/docker-compose.yml @@ -0,0 +1,33 @@ +version: "2" +services: + postgrescompose: + image: "postgres:9.5" + container_name: "postgrescompose" + hostname: "postgrescompose" + ports: + - "5432:5432" + command: "postgres" + foulkonworkercompose: + image: "tecsisa/foulkon:v0.2.0" + container_name: "foulkonworkercompose" + hostname: "foulkonworkercompose" + environment: + - FOULKON_WORKER_HOST=foulkonworkercompose + - FOULKON_WORKER_PORT=8000 + - FOULKON_ADMIN_USER=admin + - FOULKON_ADMIN_PASS=admin + - FOULKON_WORKER_LOG_TYPE=default + - FOULKON_WORKER_LOG_LEVEL=info + - FOULKON_DB=postgres + - FOULKON_DB_POSTGRES_DS=postgres://postgres:password@postgrescompose:5432/postgres?sslmode=disable + - FOULKON_DB_POSTGRES_IDLECONNS=10 + - FOULKON_DB_POSTGRES_MAXCONNS=20 + - FOULKON_DB_POSTGRES_CONNTTL=300 + - FOULKON_AUTH_TYPE=oidc + - FOULKON_AUTH_ISSUER=https://accounts.google.com + - FOULKON_AUTH_CLIENTID=google-client-identity + ports: + - "8000:8000" + command: "worker" + depends_on: + - postgrescompose diff --git a/demo/web/main.go b/demo/web/main.go new file mode 100644 index 0000000..3fc3bd6 --- /dev/null +++ b/demo/web/main.go @@ -0,0 +1,147 @@ +package main + +import ( + "bytes" + "encoding/json" + "html/template" + "log" + "net/http" + "os" + + "github.com/Sirupsen/logrus" + "github.com/julienschmidt/httprouter" +) + +// CONSTANTS +const ( + // Environment Vars + WEBHOST = "WEBHOST" + WEBPORT = "WEBPORT" + APIHOST = "APIHOST" + APIPORT = "APIPORT" + + // Operations + ADD_OPERATION = "Add" + GET_OPERATION = "Get" + PUT_OPERATION = "Put" + DELETE_OPERATION = "Delete" + LIST_OPERATION = "List" +) + +type Node struct { + // Operations + Operation string + + // URLs + WebBaseUrl string + APIBaseUrl string + + // Profile + UserId string + Token string + Roles []string + + // Table Resources + ResourceTableElements *ResourceTableElements +} + +type Resource struct { + Id string `json:"id, omitempty"` + Resource string `json:"resource, omitempty"` +} + +type ResourceTableElements struct { + Resources []Resource +} + +var mainTemplate *template.Template +var client = http.DefaultClient +var logger *logrus.Logger +var node = new(Node) + +func HandlePage(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { + err := mainTemplate.Execute(w, nil) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} + +func ListResources(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { + logger.Info("LISTING RESOURCES") + request, err := http.NewRequest(http.MethodGet, node.APIBaseUrl+"/resources", nil) + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + response, err := client.Do(request) + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer response.Body.Close() + + buffer := new(bytes.Buffer) + if _, err := buffer.ReadFrom(response.Body); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + logger.Infof("Values: %v", string(buffer.Bytes())) + + res := make([]Resource, 0) + if err := json.Unmarshal(buffer.Bytes(), &res); err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + node.ResourceTableElements.Resources = res + + err = mainTemplate.Execute(w, node) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + +} + +func main() { + // Get API Location + apiHost := os.Getenv(APIHOST) + apiPort := os.Getenv(APIPORT) + apiURL := "http://" + apiHost + ":" + apiPort + node.APIBaseUrl = apiURL + + // Get Web Location + host := os.Getenv(WEBHOST) + port := os.Getenv(WEBPORT) + webURL := "http://" + host + ":" + port + node.WebBaseUrl = webURL + + // Create template + var err error + mainTemplate, err = template.ParseGlob("tmpl/index.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + mainTemplate, err = mainTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + logger = &logrus.Logger{ + Out: os.Stdout, + Formatter: &logrus.JSONFormatter{}, + Hooks: make(logrus.LevelHooks), + Level: logrus.InfoLevel, + } + + router := httprouter.New() + router.GET("/", HandlePage) + router.POST("/", HandlePage) + + // Start server + log.Fatal(http.ListenAndServe(host+":"+port, router)) +} diff --git a/demo/web/tmpl/base/footer.html b/demo/web/tmpl/base/footer.html new file mode 100644 index 0000000..5b6e2d6 --- /dev/null +++ b/demo/web/tmpl/base/footer.html @@ -0,0 +1,3 @@ + + + diff --git a/demo/web/tmpl/base/header.html b/demo/web/tmpl/base/header.html new file mode 100644 index 0000000..e95e76f --- /dev/null +++ b/demo/web/tmpl/base/header.html @@ -0,0 +1,21 @@ + + + + + + FOULKON + + + +
+
+ Logo +
+
+

Welcome to Foulkon Example APP

+
+
+ + +
+ diff --git a/demo/web/tmpl/index.html b/demo/web/tmpl/index.html new file mode 100644 index 0000000..ba9f2ca --- /dev/null +++ b/demo/web/tmpl/index.html @@ -0,0 +1,8 @@ +{{ template "header.html" }} +
+ {{if .Token eq ""}} + You must login before you use endpoints to work with example resources. Click here to log in. + {{end}} +
+ +{{ template "footer.html" }} \ No newline at end of file From fe0f513d86946f9670f9cc62a4af95e57e6d1790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerson=20Pozo=20Gonz=C3=A1lez?= Date: Tue, 25 Oct 2016 16:51:50 +0200 Subject: [PATCH 03/18] Implements web logic --- demo/api/main.go | 5 +- demo/web/main.go | 235 ++++++++++++++++++++++++++++++--- demo/web/tmpl/add.html | 21 +++ demo/web/tmpl/base/header.html | 9 ++ demo/web/tmpl/delete.html | 19 +++ demo/web/tmpl/index.html | 6 +- demo/web/tmpl/list.html | 23 ++++ demo/web/tmpl/update.html | 21 +++ 8 files changed, 318 insertions(+), 21 deletions(-) create mode 100644 demo/web/tmpl/add.html create mode 100644 demo/web/tmpl/delete.html create mode 100644 demo/web/tmpl/list.html create mode 100644 demo/web/tmpl/update.html diff --git a/demo/api/main.go b/demo/api/main.go index ec9facb..01aa2f0 100644 --- a/demo/api/main.go +++ b/demo/api/main.go @@ -51,12 +51,13 @@ func HandleGetResource(w http.ResponseWriter, _ *http.Request, ps httprouter.Par processHttpResponse(w, response, nil, statusCode) } -func HandlePutResource(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { +func HandlePutResource(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { request := &Resource{} err := processHttpRequest(r, request) var response *Resource if err == nil { - resources[request.Id] = request.Resource + id := ps.ByName("id") + resources[id] = request.Resource response = request } processHttpResponse(w, response, err, http.StatusOK) diff --git a/demo/web/main.go b/demo/web/main.go index 3fc3bd6..66f127c 100644 --- a/demo/web/main.go +++ b/demo/web/main.go @@ -10,6 +10,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/julienschmidt/httprouter" + "strconv" ) // CONSTANTS @@ -43,6 +44,9 @@ type Node struct { // Table Resources ResourceTableElements *ResourceTableElements + + // Msg + Message string } type Resource struct { @@ -50,24 +54,85 @@ type Resource struct { Resource string `json:"resource, omitempty"` } +type UpdateResource struct { + Resource string `json:"resource, omitempty"` +} + type ResourceTableElements struct { Resources []Resource } var mainTemplate *template.Template +var listTemplate *template.Template +var addTemplate *template.Template +var removeTemplate *template.Template +var updateTemplate *template.Template var client = http.DefaultClient var logger *logrus.Logger var node = new(Node) +func createTemplates() { + var err error + mainTemplate, err = template.ParseGlob("tmpl/index.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + mainTemplate, err = mainTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + listTemplate, err = template.ParseGlob("tmpl/list.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + listTemplate, err = listTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + addTemplate, err = template.ParseGlob("tmpl/add.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + addTemplate, err = addTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + removeTemplate, err = template.ParseGlob("tmpl/delete.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + removeTemplate, err = removeTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + updateTemplate, err = template.ParseGlob("tmpl/update.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + updateTemplate, err = updateTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } +} + func HandlePage(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { - err := mainTemplate.Execute(w, nil) + err := mainTemplate.Execute(w, node) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } -func ListResources(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { - logger.Info("LISTING RESOURCES") +func HandleListResources(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { + logger.Info("Listing resources") request, err := http.NewRequest(http.MethodGet, node.APIBaseUrl+"/resources", nil) if err != nil { logger.Info(err.Error()) @@ -97,13 +162,152 @@ func ListResources(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) return } - node.ResourceTableElements.Resources = res + node.ResourceTableElements = &ResourceTableElements{ + Resources: res, + } - err = mainTemplate.Execute(w, node) + node.Message = "" + err = listTemplate.Execute(w, node) if err != nil { + logger.Info(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) } +} + +func HandleAddResource(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + if r.Method == http.MethodPost { + logger.Info("Adding resource") + r.ParseForm() + res := Resource{ + Id: r.Form.Get("id"), + Resource: r.Form.Get("resource"), + } + + jsonObject, err := json.Marshal(&res) + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + body := bytes.NewBuffer(jsonObject) + request, err := http.NewRequest(http.MethodPost, node.APIBaseUrl+"/resources", body) + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + response, err := client.Do(request) + + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if response.StatusCode == http.StatusOK { + node.Message = "Resource created!" + } else { + node.Message = "Error, status code received " + strconv.Itoa(response.StatusCode) + } + + addTemplate.Execute(w, node) + } else { + node.Message = "" + err := addTemplate.Execute(w, node) + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + } + } +} + +func HandleUpdateResource(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + if r.Method == http.MethodPost { + logger.Info("Updating resource") + r.ParseForm() + res := UpdateResource{ + Resource: r.Form.Get("resource"), + } + id := r.Form.Get("id") + + jsonObject, err := json.Marshal(&res) + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + body := bytes.NewBuffer(jsonObject) + + request, err := http.NewRequest(http.MethodPut, node.APIBaseUrl+"/resources/"+id, body) + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + response, err := client.Do(request) + + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if response.StatusCode == http.StatusOK { + node.Message = "Resource Updated!" + } else { + node.Message = "Error, status code received " + strconv.Itoa(response.StatusCode) + } + + updateTemplate.Execute(w, node) + } else { + node.Message = "" + err := updateTemplate.Execute(w, node) + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + } + } +} + +func HandleRemoveResource(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + if r.Method == http.MethodPost { + logger.Info("Removing resource") + r.ParseForm() + id := r.Form.Get("id") + + request, err := http.NewRequest(http.MethodDelete, node.APIBaseUrl+"/resources/"+id, nil) + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + response, err := client.Do(request) + + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if response.StatusCode == http.StatusNoContent { + node.Message = "Resource deleted!" + } else { + node.Message = "Error, status code received " + strconv.Itoa(response.StatusCode) + } + + removeTemplate.Execute(w, node) + } else { + node.Message = "" + err := removeTemplate.Execute(w, node) + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + } + + } } func main() { @@ -119,17 +323,8 @@ func main() { webURL := "http://" + host + ":" + port node.WebBaseUrl = webURL - // Create template - var err error - mainTemplate, err = template.ParseGlob("tmpl/index.html") - if err != nil { - log.Fatalf("Template can't be parsed: %v", err) - } - - mainTemplate, err = mainTemplate.ParseGlob("tmpl/base/*.html") - if err != nil { - log.Fatalf("Template can't be parsed: %v", err) - } + // Create templates + createTemplates() logger = &logrus.Logger{ Out: os.Stdout, @@ -137,10 +332,16 @@ func main() { Hooks: make(logrus.LevelHooks), Level: logrus.InfoLevel, } - router := httprouter.New() router.GET("/", HandlePage) router.POST("/", HandlePage) + router.GET("/add", HandleAddResource) + router.POST("/add", HandleAddResource) + router.GET("/remove", HandleRemoveResource) + router.POST("/remove", HandleRemoveResource) + router.GET("/update", HandleUpdateResource) + router.POST("/update", HandleUpdateResource) + router.GET("/list", HandleListResources) // Start server log.Fatal(http.ListenAndServe(host+":"+port, router)) diff --git a/demo/web/tmpl/add.html b/demo/web/tmpl/add.html new file mode 100644 index 0000000..0a8c08b --- /dev/null +++ b/demo/web/tmpl/add.html @@ -0,0 +1,21 @@ +{{ template "header.html" }} + +
+
+ + + + + + + + +
IDResource
+
+
+ +
+ {{ .Message }} +
+ +{{ template "footer.html" }} \ No newline at end of file diff --git a/demo/web/tmpl/base/header.html b/demo/web/tmpl/base/header.html index e95e76f..0517fba 100644 --- a/demo/web/tmpl/base/header.html +++ b/demo/web/tmpl/base/header.html @@ -16,6 +16,15 @@

Welcome to Foulkon Example APP

+
+ +
diff --git a/demo/web/tmpl/delete.html b/demo/web/tmpl/delete.html new file mode 100644 index 0000000..a01aea2 --- /dev/null +++ b/demo/web/tmpl/delete.html @@ -0,0 +1,19 @@ +{{ template "header.html" }} + +
+
+ + + + + + +
ID
+
+
+ +
+ {{ .Message }} +
+ +{{ template "footer.html" }} \ No newline at end of file diff --git a/demo/web/tmpl/index.html b/demo/web/tmpl/index.html index ba9f2ca..b0a5b6c 100644 --- a/demo/web/tmpl/index.html +++ b/demo/web/tmpl/index.html @@ -1,7 +1,9 @@ {{ template "header.html" }} +
- {{if .Token eq ""}} - You must login before you use endpoints to work with example resources. Click here to log in. + {{if eq .Token ""}} + You must login before you use endpoints to work with example resources. Click here to log in. + {{else}} {{end}}
diff --git a/demo/web/tmpl/list.html b/demo/web/tmpl/list.html new file mode 100644 index 0000000..68ff28e --- /dev/null +++ b/demo/web/tmpl/list.html @@ -0,0 +1,23 @@ +{{ template "header.html" }} + +
+

Resources

+ {{ $length := len .ResourceTableElements.Resources }} {{ if eq $length 0 }} + List empty + {{else}} + + + + + + {{range $element := .ResourceTableElements.Resources}} + + + + + {{end}} +
IDResource
{{ $element.Id }}{{ $element.Resource }}
+ {{end}} +
+ +{{ template "footer.html" }} \ No newline at end of file diff --git a/demo/web/tmpl/update.html b/demo/web/tmpl/update.html new file mode 100644 index 0000000..9032723 --- /dev/null +++ b/demo/web/tmpl/update.html @@ -0,0 +1,21 @@ +{{ template "header.html" }} + +
+
+ + + + + + + + +
IDNew resource
+
+
+ +
+ {{ .Message }} +
+ +{{ template "footer.html" }} \ No newline at end of file From 6a9325fa741a3c1b3c12b5b9fd2bc5bc3eaf3ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Wed, 26 Oct 2016 15:43:41 +0200 Subject: [PATCH 04/18] Build demo script --- GNUmakefile | 5 +- demo/Dockerfile | 15 ------ demo/api/main.go | 5 +- demo/build-demo.sh | 20 ++++++++ demo/docker-compose.yml | 33 ------------- demo/docker/Dockerfile | 22 +++++++++ demo/docker/demo-proxy.toml | 52 +++++++++++++++++++++ demo/docker/docker-compose.yml | 77 +++++++++++++++++++++++++++++++ demo/docker/entrypoint.sh | 12 +++++ demo/web/main.go | 21 ++++----- scripts/docker/docker-compose.yml | 33 ------------- 11 files changed, 200 insertions(+), 95 deletions(-) delete mode 100644 demo/Dockerfile create mode 100755 demo/build-demo.sh delete mode 100644 demo/docker-compose.yml create mode 100644 demo/docker/Dockerfile create mode 100644 demo/docker/demo-proxy.toml create mode 100644 demo/docker/docker-compose.yml create mode 100644 demo/docker/entrypoint.sh delete mode 100644 scripts/docker/docker-compose.yml diff --git a/GNUmakefile b/GNUmakefile index 1c99194..6895f0c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -19,6 +19,9 @@ deps: bin: generate format imports @sh -c "'$(PWD)/scripts/build.sh'" +demo: + @sh -c "'$(PWD)/demo/build-demo.sh'" + release: @$(MAKE) bin @@ -74,4 +77,4 @@ bootstrap: deps travis: @sh -c "'$(PWD)/scripts/travis.sh'" -.PHONY: all dev deps bin release generate format imports test vet bootstrap travis +.PHONY: all dev deps bin demo release generate format imports test vet bootstrap travis diff --git a/demo/Dockerfile b/demo/Dockerfile deleted file mode 100644 index e5e1b0f..0000000 --- a/demo/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM alpine -MAINTAINER Tecsisa - -USER root -RUN apk update && apk add ca-certificates - -# API -COPY bin/demoapi /go/bin/demoapi - -# WEB -COPY bin/demoweb /go/bin/demoweb - -ENV PATH=$PATH:/go/bin - -EXPOSE 8000 8001 \ No newline at end of file diff --git a/demo/api/main.go b/demo/api/main.go index 01aa2f0..97bda16 100644 --- a/demo/api/main.go +++ b/demo/api/main.go @@ -2,10 +2,11 @@ package main import ( "encoding/json" - "github.com/coreos/dex/pkg/log" - "github.com/julienschmidt/httprouter" "net/http" "os" + + "github.com/coreos/dex/pkg/log" + "github.com/julienschmidt/httprouter" ) // CONSTANTS diff --git a/demo/build-demo.sh b/demo/build-demo.sh new file mode 100755 index 0000000..b03e59d --- /dev/null +++ b/demo/build-demo.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +echo "----> Building Demo..." + +echo "----> Compiling demo example apps..." +# Make sure $GOPATH is set +CGO_ENABLED=0 go install github.com/Tecsisa/foulkon/demo/api +CGO_ENABLED=0 go install github.com/Tecsisa/foulkon/demo/web + +echo "----> Moving compiled files to GOROOT path..." +mkdir bin/ 2>/dev/null +cp $GOPATH/bin/api ./bin +cp $GOPATH/bin/web ./bin + +echo "----> Building Docker demo images..." +docker build -t tecsisa/foulkondemo -f demo/docker/Dockerfile . + +echo "----> Starting Docker Compose..." +docker-compose -f demo/docker/docker-compose.yml up --force-recreate --abort-on-container-exit + diff --git a/demo/docker-compose.yml b/demo/docker-compose.yml deleted file mode 100644 index 3c3e892..0000000 --- a/demo/docker-compose.yml +++ /dev/null @@ -1,33 +0,0 @@ -version: "2" -services: - postgrescompose: - image: "postgres:9.5" - container_name: "postgrescompose" - hostname: "postgrescompose" - ports: - - "5432:5432" - command: "postgres" - foulkonworkercompose: - image: "tecsisa/foulkon:v0.2.0" - container_name: "foulkonworkercompose" - hostname: "foulkonworkercompose" - environment: - - FOULKON_WORKER_HOST=foulkonworkercompose - - FOULKON_WORKER_PORT=8000 - - FOULKON_ADMIN_USER=admin - - FOULKON_ADMIN_PASS=admin - - FOULKON_WORKER_LOG_TYPE=default - - FOULKON_WORKER_LOG_LEVEL=info - - FOULKON_DB=postgres - - FOULKON_DB_POSTGRES_DS=postgres://postgres:password@postgrescompose:5432/postgres?sslmode=disable - - FOULKON_DB_POSTGRES_IDLECONNS=10 - - FOULKON_DB_POSTGRES_MAXCONNS=20 - - FOULKON_DB_POSTGRES_CONNTTL=300 - - FOULKON_AUTH_TYPE=oidc - - FOULKON_AUTH_ISSUER=https://accounts.google.com - - FOULKON_AUTH_CLIENTID=google-client-identity - ports: - - "8000:8000" - command: "worker" - depends_on: - - postgrescompose diff --git a/demo/docker/Dockerfile b/demo/docker/Dockerfile new file mode 100644 index 0000000..39e55de --- /dev/null +++ b/demo/docker/Dockerfile @@ -0,0 +1,22 @@ +FROM tecsisa/foulkon:v0.2.0 +MAINTAINER Tecsisa + +# Copy resources of this API +COPY demo/docker/demo-proxy.toml /proxy.toml + +# API +COPY bin/api /go/bin/api + +# WEB +COPY bin/web /go/bin/web +COPY demo/web/tmpl /tmpl + +# Entrypoint +ADD demo/docker/entrypoint.sh /go/bin/entrypoint.sh +RUN chmod 750 /go/bin/* + +ENV PATH=$PATH:/go/bin + +EXPOSE 8000 8001 8100 8101 + +ENTRYPOINT ["/go/bin/entrypoint.sh"] \ No newline at end of file diff --git a/demo/docker/demo-proxy.toml b/demo/docker/demo-proxy.toml new file mode 100644 index 0000000..04d75f9 --- /dev/null +++ b/demo/docker/demo-proxy.toml @@ -0,0 +1,52 @@ +# Server config +[server] +host = "${FOULKON_PROXY_HOST}" +port = "${FOULKON_PROXY_PORT}" +certfile = "${FOULKON_PROXY_CERT_FILE_PATH}" +keyfile = "${FOULKON_PROXY_KEY_FILE_PATH}" +worker-host = "${FOULKON_WORKER_URL}" + +# Logger +[logger] +type = "${FOULKON_PROXY_LOG_TYPE}" +level = "debug" + # Directory for file configuration + [logger.file] + dir = "${FOULKON_PROXY_LOG_PATH}" + +# Resources definition example +[[resources]] + id = "resource1" + host = "http://foulkondemoapicompose:8100" + url = "/resources" + method = "GET" + urn = "urn:ews:foulkon:demo1:resource/list" + action = "example:list" +[[resources]] + id = "resource2" + host = "http://foulkondemoapicompose:8100" + url = "/resources" + method = "POST" + urn = "urn:ews:foulkon:demo1:resource/add" + action = "example:add" +[[resources]] + id = "resource3" + host = "http://foulkondemoapicompose:8100" + url = "/resources/:id" + method = "GET" + urn = "urn:ews:foulkon:demo1:resource/myresources/{id}" + action = "example:get" +[[resources]] + id = "resource4" + host = "http://foulkondemoapicompose:8100" + url = "/resources/:id" + method = "PUT" + urn = "urn:ews:foulkon:demo1:resource/myresources/{id}" + action = "example:update" +[[resources]] + id = "resource5" + host = "http://foulkondemoapicompose:8100" + url = "/resources/:id" + method = "DELETE" + urn = "urn:ews:foulkon:demo1:resource/myresources/{id}" + action = "example:delete" \ No newline at end of file diff --git a/demo/docker/docker-compose.yml b/demo/docker/docker-compose.yml new file mode 100644 index 0000000..979c121 --- /dev/null +++ b/demo/docker/docker-compose.yml @@ -0,0 +1,77 @@ +version: "2" +services: + postgrescompose: + image: "postgres:9.5" + container_name: "postgrescompose" + hostname: "postgrescompose" + ports: + - "5432:5432" + command: "postgres" + foulkonworkercompose: + image: "tecsisa/foulkon:v0.2.0" + container_name: "foulkonworkercompose" + hostname: "foulkonworkercompose" + environment: + - FOULKON_WORKER_HOST=foulkonworkercompose + - FOULKON_WORKER_PORT=8000 + - FOULKON_ADMIN_USER=admin + - FOULKON_ADMIN_PASS=admin + - FOULKON_WORKER_LOG_TYPE=default + - FOULKON_WORKER_LOG_LEVEL=info + - FOULKON_DB=postgres + - FOULKON_DB_POSTGRES_DS=postgres://postgres:password@postgrescompose:5432/postgres?sslmode=disable + - FOULKON_DB_POSTGRES_IDLECONNS=10 + - FOULKON_DB_POSTGRES_MAXCONNS=20 + - FOULKON_DB_POSTGRES_CONNTTL=300 + - FOULKON_AUTH_TYPE=oidc + - FOULKON_AUTH_ISSUER=https://accounts.google.com + - FOULKON_AUTH_CLIENTID=google-client-identity + ports: + - "8000:8000" + command: "worker" + depends_on: + - postgrescompose + foulkondemoproxycompose: + image: "tecsisa/foulkondemo:latest" + container_name: "foulkondemoproxycompose" + hostname: "foulkondemoproxycompose" + environment: + - FOULKON_PROXY_HOST=foulkondemoproxycompose + - FOULKON_PROXY_PORT=8001 + - FOULKON_PROXY_LOG_TYPE=default + - FOULKON_PROXY_LOG_LEVEL=info + - FOULKON_WORKER_URL=http://foulkonworkercompose:8000 + ports: + - "8001:8001" + command: "proxy" + depends_on: + - postgrescompose + - foulkonworkercompose + foulkondemoapicompose: + image: "tecsisa/foulkondemo:latest" + container_name: "foulkondemoapicompose" + hostname: "foulkondemoapicompose" + environment: + - APIHOST=foulkondemoapicompose + - APIPORT=8100 + ports: + - "8100:8100" + command: "api" + depends_on: + - postgrescompose + - foulkonworkercompose + foulkondemowebcompose: + image: "tecsisa/foulkondemo" + container_name: "foulkondemowebcompose" + hostname: "foulkondemowebcompose" + environment: + - APIHOST=foulkondemoproxycompose + - APIPORT=8001 + - WEBHOST=foulkondemowebcompose + - WEBPORT=8101 + ports: + - "8101:8101" + command: "web" + depends_on: + - postgrescompose + - foulkonworkercompose diff --git a/demo/docker/entrypoint.sh b/demo/docker/entrypoint.sh new file mode 100644 index 0000000..57df9f2 --- /dev/null +++ b/demo/docker/entrypoint.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +usage() { echo "Usage: proxy|api|web" 1>&2; exit 1; } +if [ "$1" = 'proxy' ]; then + proxy -proxy-file=/proxy.toml +elif [ "$1" = 'api' ]; then + api +elif [ "$1" = 'web' ]; then + web +else + usage +fi \ No newline at end of file diff --git a/demo/web/main.go b/demo/web/main.go index 66f127c..215a80a 100644 --- a/demo/web/main.go +++ b/demo/web/main.go @@ -8,9 +8,10 @@ import ( "net/http" "os" + "strconv" + "github.com/Sirupsen/logrus" "github.com/julienschmidt/httprouter" - "strconv" ) // CONSTANTS @@ -20,19 +21,9 @@ const ( WEBPORT = "WEBPORT" APIHOST = "APIHOST" APIPORT = "APIPORT" - - // Operations - ADD_OPERATION = "Add" - GET_OPERATION = "Get" - PUT_OPERATION = "Put" - DELETE_OPERATION = "Delete" - LIST_OPERATION = "List" ) type Node struct { - // Operations - Operation string - // URLs WebBaseUrl string APIBaseUrl string @@ -139,6 +130,8 @@ func HandleListResources(w http.ResponseWriter, _ *http.Request, _ httprouter.Pa http.Error(w, err.Error(), http.StatusInternalServerError) return } + // TODO rsoleto: Change this when we have a oidc login + request.SetBasicAuth("admin", "admin") response, err := client.Do(request) if err != nil { @@ -198,6 +191,8 @@ func HandleAddResource(w http.ResponseWriter, r *http.Request, _ httprouter.Para http.Error(w, err.Error(), http.StatusInternalServerError) return } + // TODO rsoleto: Change this when we have a oidc login + request.SetBasicAuth("admin", "admin") response, err := client.Do(request) if err != nil { @@ -247,6 +242,8 @@ func HandleUpdateResource(w http.ResponseWriter, r *http.Request, _ httprouter.P http.Error(w, err.Error(), http.StatusInternalServerError) return } + // TODO rsoleto: Change this when we have a oidc login + request.SetBasicAuth("admin", "admin") response, err := client.Do(request) if err != nil { @@ -284,6 +281,8 @@ func HandleRemoveResource(w http.ResponseWriter, r *http.Request, _ httprouter.P http.Error(w, err.Error(), http.StatusInternalServerError) return } + // TODO rsoleto: Change this when we have a oidc login + request.SetBasicAuth("admin", "admin") response, err := client.Do(request) if err != nil { diff --git a/scripts/docker/docker-compose.yml b/scripts/docker/docker-compose.yml deleted file mode 100644 index 3c3e892..0000000 --- a/scripts/docker/docker-compose.yml +++ /dev/null @@ -1,33 +0,0 @@ -version: "2" -services: - postgrescompose: - image: "postgres:9.5" - container_name: "postgrescompose" - hostname: "postgrescompose" - ports: - - "5432:5432" - command: "postgres" - foulkonworkercompose: - image: "tecsisa/foulkon:v0.2.0" - container_name: "foulkonworkercompose" - hostname: "foulkonworkercompose" - environment: - - FOULKON_WORKER_HOST=foulkonworkercompose - - FOULKON_WORKER_PORT=8000 - - FOULKON_ADMIN_USER=admin - - FOULKON_ADMIN_PASS=admin - - FOULKON_WORKER_LOG_TYPE=default - - FOULKON_WORKER_LOG_LEVEL=info - - FOULKON_DB=postgres - - FOULKON_DB_POSTGRES_DS=postgres://postgres:password@postgrescompose:5432/postgres?sslmode=disable - - FOULKON_DB_POSTGRES_IDLECONNS=10 - - FOULKON_DB_POSTGRES_MAXCONNS=20 - - FOULKON_DB_POSTGRES_CONNTTL=300 - - FOULKON_AUTH_TYPE=oidc - - FOULKON_AUTH_ISSUER=https://accounts.google.com - - FOULKON_AUTH_CLIENTID=google-client-identity - ports: - - "8000:8000" - command: "worker" - depends_on: - - postgrescompose From f4531fc71b15e821548fe416533529d745d26358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Fri, 28 Oct 2016 09:58:39 +0200 Subject: [PATCH 05/18] updated templates and script to start with "make demo" --- demo/api/main.go | 140 +++++++++++++- demo/build-demo.sh | 6 +- demo/docker/demo-proxy.toml | 6 +- demo/docker/docker-compose.yml | 11 +- demo/web/main.go | 323 +++++++++++++++++++++++---------- demo/web/tmpl/base/header.html | 1 + demo/web/tmpl/error.html | 10 + demo/web/tmpl/index.html | 12 +- glide.lock | 26 +++ glide.yaml | 5 +- 10 files changed, 431 insertions(+), 109 deletions(-) create mode 100644 demo/web/tmpl/error.html diff --git a/demo/api/main.go b/demo/api/main.go index 97bda16..401a019 100644 --- a/demo/api/main.go +++ b/demo/api/main.go @@ -5,15 +5,18 @@ import ( "net/http" "os" - "github.com/coreos/dex/pkg/log" + "bytes" + "github.com/Sirupsen/logrus" "github.com/julienschmidt/httprouter" ) // CONSTANTS const ( // Environment Vars - HOST = "APIHOST" - PORT = "APIPORT" + HOST = "APIHOST" + PORT = "APIPORT" + FOULKONHOST = "FOULKON_WORKER_HOST" + FOULKONPORT = "FOULKON_WORKER_PORT" // HTTP Constants RESOURCE_ID = "id" @@ -25,6 +28,7 @@ type Resource struct { } var resources map[string]string +var logger *logrus.Logger func HandleAddResource(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { request := &Resource{} @@ -85,6 +89,16 @@ func HandleListResources(w http.ResponseWriter, _ *http.Request, _ httprouter.Pa func main() { + logger = &logrus.Logger{ + Out: os.Stdout, + Formatter: &logrus.JSONFormatter{}, + Hooks: make(logrus.LevelHooks), + Level: logrus.InfoLevel, + } + + // Startup roles + createRolesAndPolicies() + // Create the muxer to handle the actual endpoints router := httprouter.New() @@ -98,7 +112,8 @@ func main() { resources = make(map[string]string) host := os.Getenv(HOST) port := os.Getenv(PORT) - log.Fatal(http.ListenAndServe(host+":"+port, router)) + logger.Infof("Server running in %v:%v", host, port) + logger.Fatal(http.ListenAndServe(host+":"+port, router)) } @@ -131,6 +146,8 @@ func processHttpResponse(w http.ResponseWriter, response interface{}, err error, } } + w.WriteHeader(responseCode) + switch responseCode { case http.StatusOK: w.Write(data) @@ -138,6 +155,119 @@ func processHttpResponse(w http.ResponseWriter, response interface{}, err error, w.Write(data) } - w.WriteHeader(responseCode) +} + +func createRolesAndPolicies() { + foulkonhost := os.Getenv(FOULKONHOST) + foulkonport := os.Getenv(FOULKONPORT) + url := "http://" + foulkonhost + ":" + foulkonport + "/api/v1" + + createGroupFunc := func(name, path string) error { + + type CreateGroupRequest struct { + Name string `json:"name, omitempty"` + Path string `json:"path, omitempty"` + } + var body *bytes.Buffer + data := &CreateGroupRequest{ + Name: name, + Path: path, + } + + jsonObject, _ := json.Marshal(data) + body = bytes.NewBuffer(jsonObject) + + req, _ := http.NewRequest(http.MethodPost, url+"/organizations/demo/groups", body) + req.SetBasicAuth("admin", "admin") + + _, err := http.DefaultClient.Do(req) + return err + } + + type Statement struct { + Effect string `json:"effect, omitempty"` + Actions []string `json:"actions, omitempty"` + Resources []string `json:"resources, omitempty"` + } + + createPolicyAndAttachToGroup := func(name, path, groupName string, statements []Statement) error { + client := http.DefaultClient + type CreatePolicyRequest struct { + Name string `json:"name, omitempty"` + Path string `json:"path, omitempty"` + Statements []Statement `json:"statements, omitempty"` + } + var body *bytes.Buffer + data := &CreatePolicyRequest{ + Name: name, + Path: path, + Statements: statements, + } + + jsonObject, _ := json.Marshal(data) + body = bytes.NewBuffer(jsonObject) + + req, _ := http.NewRequest(http.MethodPost, url+"/organizations/demo/policies", body) + req.SetBasicAuth("admin", "admin") + + _, err := client.Do(req) + if err != nil { + return err + } + + // Attach + req, _ = http.NewRequest(http.MethodPost, url+"/organizations/demo/groups/"+groupName+"/policies/"+name, nil) + req.SetBasicAuth("admin", "admin") + + _, err = client.Do(req) + if err != nil { + return err + } + + return nil + } + + // Create read role + err := createGroupFunc("read", "/path/") + if err != nil { + logger.Fatal(err) + } + statements := []Statement{ + { + Effect: "allow", + Actions: []string{"example:list", "example:get"}, + Resources: []string{ + "urn:ews:foulkon:demo1:resource/list", + "urn:ews:foulkon:demo1:resource/demoresources/*", + }, + }, + } + + err = createPolicyAndAttachToGroup("read-policy", "/path/", "read", statements) + if err != nil { + logger.Fatal(err) + } + + // Create read write role + err = createGroupFunc("read-write", "/path/") + if err != nil { + logger.Fatal(err) + } + statements2 := []Statement{ + { + Effect: "allow", + Actions: []string{"example:list", "example:get", "example:add", "example:update", "example:delete"}, + Resources: []string{ + "urn:ews:foulkon:demo1:resource/list", + "urn:ews:foulkon:demo1:resource/demoresources/*", + "urn:ews:foulkon:demo1:resource/add", + }, + }, + } + + err = createPolicyAndAttachToGroup("read-write-policy", "/path/", "read-write", statements2) + if err != nil { + logger.Fatal(err) + } } diff --git a/demo/build-demo.sh b/demo/build-demo.sh index b03e59d..db9352a 100755 --- a/demo/build-demo.sh +++ b/demo/build-demo.sh @@ -4,8 +4,8 @@ echo "----> Building Demo..." echo "----> Compiling demo example apps..." # Make sure $GOPATH is set -CGO_ENABLED=0 go install github.com/Tecsisa/foulkon/demo/api -CGO_ENABLED=0 go install github.com/Tecsisa/foulkon/demo/web +CGO_ENABLED=0 go install github.com/Tecsisa/foulkon/demo/api || exit 1 +CGO_ENABLED=0 go install github.com/Tecsisa/foulkon/demo/web || exit 1 echo "----> Moving compiled files to GOROOT path..." mkdir bin/ 2>/dev/null @@ -13,7 +13,7 @@ cp $GOPATH/bin/api ./bin cp $GOPATH/bin/web ./bin echo "----> Building Docker demo images..." -docker build -t tecsisa/foulkondemo -f demo/docker/Dockerfile . +docker build -t tecsisa/foulkondemo -f demo/docker/Dockerfile . >/dev/null || exit 1 echo "----> Starting Docker Compose..." docker-compose -f demo/docker/docker-compose.yml up --force-recreate --abort-on-container-exit diff --git a/demo/docker/demo-proxy.toml b/demo/docker/demo-proxy.toml index 04d75f9..eae2d17 100644 --- a/demo/docker/demo-proxy.toml +++ b/demo/docker/demo-proxy.toml @@ -34,19 +34,19 @@ level = "debug" host = "http://foulkondemoapicompose:8100" url = "/resources/:id" method = "GET" - urn = "urn:ews:foulkon:demo1:resource/myresources/{id}" + urn = "urn:ews:foulkon:demo1:resource/demoresources/{id}" action = "example:get" [[resources]] id = "resource4" host = "http://foulkondemoapicompose:8100" url = "/resources/:id" method = "PUT" - urn = "urn:ews:foulkon:demo1:resource/myresources/{id}" + urn = "urn:ews:foulkon:demo1:resource/demoresources/{id}" action = "example:update" [[resources]] id = "resource5" host = "http://foulkondemoapicompose:8100" url = "/resources/:id" method = "DELETE" - urn = "urn:ews:foulkon:demo1:resource/myresources/{id}" + urn = "urn:ews:foulkon:demo1:resource/demoresources/{id}" action = "example:delete" \ No newline at end of file diff --git a/demo/docker/docker-compose.yml b/demo/docker/docker-compose.yml index 979c121..941b150 100644 --- a/demo/docker/docker-compose.yml +++ b/demo/docker/docker-compose.yml @@ -4,8 +4,6 @@ services: image: "postgres:9.5" container_name: "postgrescompose" hostname: "postgrescompose" - ports: - - "5432:5432" command: "postgres" foulkonworkercompose: image: "tecsisa/foulkon:v0.2.0" @@ -25,7 +23,7 @@ services: - FOULKON_DB_POSTGRES_CONNTTL=300 - FOULKON_AUTH_TYPE=oidc - FOULKON_AUTH_ISSUER=https://accounts.google.com - - FOULKON_AUTH_CLIENTID=google-client-identity + - FOULKON_AUTH_CLIENTID=953874647871-gco7i6urt1i4clafgoeuo2gnicj2sg2q.apps.googleusercontent.com ports: - "8000:8000" command: "worker" @@ -52,6 +50,8 @@ services: container_name: "foulkondemoapicompose" hostname: "foulkondemoapicompose" environment: + - FOULKON_WORKER_HOST=foulkonworkercompose + - FOULKON_WORKER_PORT=8000 - APIHOST=foulkondemoapicompose - APIPORT=8100 ports: @@ -67,8 +67,11 @@ services: environment: - APIHOST=foulkondemoproxycompose - APIPORT=8001 - - WEBHOST=foulkondemowebcompose + - WEBHOST=localhost - WEBPORT=8101 + - OIDC_CLIENT_ID=953874647871-gco7i6urt1i4clafgoeuo2gnicj2sg2q.apps.googleusercontent.com + - OIDC_CLIENT_SECRET=T2P-Q8hxq5jfdR5EhPFGuFVs + - OIDC_IDP_DISCOVERY=https://accounts.google.com ports: - "8101:8101" command: "web" diff --git a/demo/web/main.go b/demo/web/main.go index 215a80a..bcb3e4f 100644 --- a/demo/web/main.go +++ b/demo/web/main.go @@ -10,7 +10,11 @@ import ( "strconv" + "fmt" + "net/url" + "github.com/Sirupsen/logrus" + "github.com/coreos/go-oidc/oidc" "github.com/julienschmidt/httprouter" ) @@ -21,6 +25,11 @@ const ( WEBPORT = "WEBPORT" APIHOST = "APIHOST" APIPORT = "APIPORT" + + // OIDC + OIDCCLIENTID = "OIDC_CLIENT_ID" + OIDCCLIENTSECRET = "OIDC_CLIENT_SECRET" + OIDCIDPDISCOVERY = "OIDC_IDP_DISCOVERY" ) type Node struct { @@ -38,6 +47,10 @@ type Node struct { // Msg Message string + + // Error + HttpErrorStatusCode int + ErrorMessage string } type Resource struct { @@ -58,63 +71,64 @@ var listTemplate *template.Template var addTemplate *template.Template var removeTemplate *template.Template var updateTemplate *template.Template +var errorTemplate *template.Template var client = http.DefaultClient var logger *logrus.Logger var node = new(Node) -func createTemplates() { - var err error - mainTemplate, err = template.ParseGlob("tmpl/index.html") - if err != nil { - log.Fatalf("Template can't be parsed: %v", err) - } - - mainTemplate, err = mainTemplate.ParseGlob("tmpl/base/*.html") - if err != nil { - log.Fatalf("Template can't be parsed: %v", err) - } - - listTemplate, err = template.ParseGlob("tmpl/list.html") - if err != nil { - log.Fatalf("Template can't be parsed: %v", err) - } +func main() { + // Get API Location + apiHost := os.Getenv(APIHOST) + apiPort := os.Getenv(APIPORT) + apiURL := "http://" + apiHost + ":" + apiPort + node.APIBaseUrl = apiURL - listTemplate, err = listTemplate.ParseGlob("tmpl/base/*.html") - if err != nil { - log.Fatalf("Template can't be parsed: %v", err) - } + // Get Web Location + host := os.Getenv(WEBHOST) + port := os.Getenv(WEBPORT) + webURL := "http://" + host + ":" + port + node.WebBaseUrl = webURL - addTemplate, err = template.ParseGlob("tmpl/add.html") - if err != nil { - log.Fatalf("Template can't be parsed: %v", err) + logger = &logrus.Logger{ + Out: os.Stdout, + Formatter: &logrus.JSONFormatter{}, + Hooks: make(logrus.LevelHooks), + Level: logrus.InfoLevel, } - addTemplate, err = addTemplate.ParseGlob("tmpl/base/*.html") + // Create oidc client + client, err := createOidcClient(host, port) if err != nil { - log.Fatalf("Template can't be parsed: %v", err) + logger.Fatalf("There was an error creating oidc client: %v", err) } - removeTemplate, err = template.ParseGlob("tmpl/delete.html") - if err != nil { - log.Fatalf("Template can't be parsed: %v", err) + if client == nil { + logger.Fatal("Nil OIDC client") } - removeTemplate, err = removeTemplate.ParseGlob("tmpl/base/*.html") - if err != nil { - log.Fatalf("Template can't be parsed: %v", err) - } + // Create templates + createTemplates() - updateTemplate, err = template.ParseGlob("tmpl/update.html") - if err != nil { - log.Fatalf("Template can't be parsed: %v", err) - } + router := httprouter.New() + router.GET("/", HandlePage) + router.POST("/", HandlePage) + router.GET("/add", HandleAddResource) + router.POST("/add", HandleAddResource) + router.GET("/remove", HandleRemoveResource) + router.POST("/remove", HandleRemoveResource) + router.GET("/update", HandleUpdateResource) + router.POST("/update", HandleUpdateResource) + router.GET("/list", HandleListResources) + router.GET("/login", HandleLoginFunc(client)) + router.GET("/callback", HandleCallbackFunc(client)) - updateTemplate, err = updateTemplate.ParseGlob("tmpl/base/*.html") - if err != nil { - log.Fatalf("Template can't be parsed: %v", err) - } + // Start server + logger.Infof("Server running in %v:%v", host, port) + log.Fatal(http.ListenAndServe(":"+port, router)) } +// HANDLERS + func HandlePage(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { err := mainTemplate.Execute(w, node) if err != nil { @@ -123,15 +137,13 @@ func HandlePage(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { } func HandleListResources(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { - logger.Info("Listing resources") request, err := http.NewRequest(http.MethodGet, node.APIBaseUrl+"/resources", nil) if err != nil { logger.Info(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } - // TODO rsoleto: Change this when we have a oidc login - request.SetBasicAuth("admin", "admin") + request.Header.Set("Authorization", "Bearer "+node.Token) response, err := client.Do(request) if err != nil { @@ -141,12 +153,16 @@ func HandleListResources(w http.ResponseWriter, _ *http.Request, _ httprouter.Pa } defer response.Body.Close() + if response.StatusCode != http.StatusOK { + renderErrorTemplate(w, response.StatusCode, fmt.Sprintf("List method error. Error code: %v", http.StatusText(response.StatusCode))) + return + } + buffer := new(bytes.Buffer) if _, err := buffer.ReadFrom(response.Body); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - logger.Infof("Values: %v", string(buffer.Bytes())) res := make([]Resource, 0) if err := json.Unmarshal(buffer.Bytes(), &res); err != nil { @@ -191,15 +207,18 @@ func HandleAddResource(w http.ResponseWriter, r *http.Request, _ httprouter.Para http.Error(w, err.Error(), http.StatusInternalServerError) return } - // TODO rsoleto: Change this when we have a oidc login - request.SetBasicAuth("admin", "admin") - response, err := client.Do(request) + request.Header.Set("Authorization", "Bearer "+node.Token) + response, err := client.Do(request) if err != nil { logger.Info(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } + if response.StatusCode != http.StatusOK { + renderErrorTemplate(w, response.StatusCode, fmt.Sprintf("Add method error. Error code: %v", http.StatusText(response.StatusCode))) + return + } if response.StatusCode == http.StatusOK { node.Message = "Resource created!" @@ -242,22 +261,20 @@ func HandleUpdateResource(w http.ResponseWriter, r *http.Request, _ httprouter.P http.Error(w, err.Error(), http.StatusInternalServerError) return } - // TODO rsoleto: Change this when we have a oidc login - request.SetBasicAuth("admin", "admin") - response, err := client.Do(request) + request.Header.Set("Authorization", "Bearer "+node.Token) + response, err := client.Do(request) if err != nil { logger.Info(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } - - if response.StatusCode == http.StatusOK { - node.Message = "Resource Updated!" - } else { - node.Message = "Error, status code received " + strconv.Itoa(response.StatusCode) + if response.StatusCode != http.StatusOK { + renderErrorTemplate(w, response.StatusCode, fmt.Sprintf("Update method not available. Error code: %v", http.StatusText(response.StatusCode))) + return } + node.Message = "Resource Updated!" updateTemplate.Execute(w, node) } else { node.Message = "" @@ -281,8 +298,7 @@ func HandleRemoveResource(w http.ResponseWriter, r *http.Request, _ httprouter.P http.Error(w, err.Error(), http.StatusInternalServerError) return } - // TODO rsoleto: Change this when we have a oidc login - request.SetBasicAuth("admin", "admin") + request.Header.Set("Authorization", "Bearer "+node.Token) response, err := client.Do(request) if err != nil { @@ -291,12 +307,12 @@ func HandleRemoveResource(w http.ResponseWriter, r *http.Request, _ httprouter.P return } - if response.StatusCode == http.StatusNoContent { - node.Message = "Resource deleted!" - } else { - node.Message = "Error, status code received " + strconv.Itoa(response.StatusCode) + if response.StatusCode != http.StatusNoContent { + renderErrorTemplate(w, response.StatusCode, fmt.Sprintf("Remove method not available. Error code: %v", http.StatusText(response.StatusCode))) + return } + node.Message = "Resource deleted!" removeTemplate.Execute(w, node) } else { node.Message = "" @@ -309,39 +325,164 @@ func HandleRemoveResource(w http.ResponseWriter, r *http.Request, _ httprouter.P } } -func main() { - // Get API Location - apiHost := os.Getenv(APIHOST) - apiPort := os.Getenv(APIPORT) - apiURL := "http://" + apiHost + ":" + apiPort - node.APIBaseUrl = apiURL +func HandleLoginFunc(c *oidc.Client) httprouter.Handle { + return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + oac, err := c.OAuthClient() + if err != nil { + panic("unable to proceed") + } - // Get Web Location - host := os.Getenv(WEBHOST) - port := os.Getenv(WEBPORT) - webURL := "http://" + host + ":" + port - node.WebBaseUrl = webURL + u, err := url.Parse(oac.AuthCodeURL("", "", "")) + if err != nil { + panic("unable to proceed") + } + http.Redirect(w, r, u.String(), http.StatusFound) + } +} - // Create templates - createTemplates() +func HandleCallbackFunc(c *oidc.Client) httprouter.Handle { + return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + code := r.URL.Query().Get("code") + if code == "" { + renderErrorTemplate(w, http.StatusBadRequest, fmt.Sprint("code query param must be set")) + return + } - logger = &logrus.Logger{ - Out: os.Stdout, - Formatter: &logrus.JSONFormatter{}, - Hooks: make(logrus.LevelHooks), - Level: logrus.InfoLevel, + tok, err := c.ExchangeAuthCode(code) + if err != nil { + renderErrorTemplate(w, http.StatusBadRequest, fmt.Sprintf("unable to verify auth code with issuer: %v", err)) + return + } + + claims, err := tok.Claims() + if err != nil { + renderErrorTemplate(w, http.StatusBadRequest, fmt.Sprintf("unable to construct claims: %v", err)) + return + } + + node.Token = tok.Encode() + node.UserId, _, _ = claims.StringClaim("sub") + + http.Redirect(w, r, node.WebBaseUrl, http.StatusFound) } - router := httprouter.New() - router.GET("/", HandlePage) - router.POST("/", HandlePage) - router.GET("/add", HandleAddResource) - router.POST("/add", HandleAddResource) - router.GET("/remove", HandleRemoveResource) - router.POST("/remove", HandleRemoveResource) - router.GET("/update", HandleUpdateResource) - router.POST("/update", HandleUpdateResource) - router.GET("/list", HandleListResources) +} - // Start server - log.Fatal(http.ListenAndServe(host+":"+port, router)) +// Aux methods + +func createTemplates() { + var err error + mainTemplate, err = template.ParseGlob("tmpl/index.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + mainTemplate, err = mainTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + listTemplate, err = template.ParseGlob("tmpl/list.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + listTemplate, err = listTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + addTemplate, err = template.ParseGlob("tmpl/add.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + addTemplate, err = addTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + removeTemplate, err = template.ParseGlob("tmpl/delete.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + removeTemplate, err = removeTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + updateTemplate, err = template.ParseGlob("tmpl/update.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + updateTemplate, err = updateTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + errorTemplate, err = template.ParseGlob("tmpl/error.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } + + errorTemplate, err = errorTemplate.ParseGlob("tmpl/base/*.html") + if err != nil { + log.Fatalf("Template can't be parsed: %v", err) + } +} + +func createOidcClient(host, port string) (*oidc.Client, error) { + // OIDC client basics + redirectURL := "http://" + host + ":" + port + "/callback" + discovery := os.Getenv(OIDCIDPDISCOVERY) + + // OIDC client credentials + cc := oidc.ClientCredentials{ + ID: os.Getenv(OIDCCLIENTID), + Secret: os.Getenv(OIDCCLIENTSECRET), + } + + logger.Infof("Configured OIDC client with values: redirectURL: %v, IDP discovery: %v", redirectURL, discovery) + + var cfg oidc.ProviderConfig + var err error + /*for {*/ + cfg, err = oidc.FetchProviderConfig(http.DefaultClient, discovery) + if err != nil { + return nil, err + } + /* + sleep := 3 * time.Second + logger.Infof("failed fetching provider config, trying again in %v: %v", sleep, err) + time.Sleep(sleep) + }*/ + + logger.Infof("fetched provider config from %s: %#v", discovery, cfg) + + ccfg := oidc.ClientConfig{ + ProviderConfig: cfg, + Credentials: cc, + RedirectURL: redirectURL, + } + + oidcClient, err := oidc.NewClient(ccfg) + if err != nil { + return nil, err + } + + oidcClient.SyncProviderConfig(discovery) + + return oidcClient, nil + +} + +func renderErrorTemplate(w http.ResponseWriter, code int, msg string) { + node.HttpErrorStatusCode = code + node.ErrorMessage = msg + err := errorTemplate.Execute(w, node) + if err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + } } diff --git a/demo/web/tmpl/base/header.html b/demo/web/tmpl/base/header.html index 0517fba..14d53e3 100644 --- a/demo/web/tmpl/base/header.html +++ b/demo/web/tmpl/base/header.html @@ -28,3 +28,4 @@

Welcome to Foulkon Example APP

+ diff --git a/demo/web/tmpl/error.html b/demo/web/tmpl/error.html new file mode 100644 index 0000000..93d41a4 --- /dev/null +++ b/demo/web/tmpl/error.html @@ -0,0 +1,10 @@ +{{ template "header.html" }} + +
+ {{.HttpErrorStatusCode}} +
+
+ {{.ErrorMessage}} +
+ +{{ template "footer.html" }} \ No newline at end of file diff --git a/demo/web/tmpl/index.html b/demo/web/tmpl/index.html index b0a5b6c..bb62eb5 100644 --- a/demo/web/tmpl/index.html +++ b/demo/web/tmpl/index.html @@ -2,8 +2,18 @@
{{if eq .Token ""}} - You must login before you use endpoints to work with example resources. Click here to log in. + You must login before you use endpoints to work with example resources. Click here to log in. {{else}} + + + + + + + + + +
User identifier{{.UserId}}
RolesEMPTY YET
{{end}}
diff --git a/glide.lock b/glide.lock index a8e6bef..2628ef7 100644 --- a/glide.lock +++ b/glide.lock @@ -1,6 +1,30 @@ +<<<<<<< HEAD hash: 93d9eba9da07ecb1e8de03b355a36f05d853193e3107852c68713fd7aac5fd3c updated: 2017-09-04T10:16:05.262507613+02:00 +======= +hash: f982b82d1f05b3ba8a0157938c1b843fbc0226b7adb6e78f3f00f806cd26f88c +updated: 2016-10-27T12:24:03.814586358+02:00 +>>>>>>> updated templates and script to start with "make demo" imports: +- name: github.com/coreos/dex + version: 4b9bdf163db85373f3ea59bb227dec445c618cbf + subpackages: + - pkg/log +- name: github.com/coreos/go-oidc + version: 9fae754a41cbdc3be9cb97a180eb323b625db614 + subpackages: + - http + - jose + - key + - oauth2 + - oidc +- name: github.com/coreos/pkg + version: fa94270d4bac0d8ae5dc6b71894e251aada93f74 + subpackages: + - flagutil + - health + - httputil + - timeutil - name: github.com/dgrijalva/jwt-go version: 24c63f56522a87ec5339cc3567883f1039378fdb - name: github.com/emanoelxavier/openid2go @@ -11,6 +35,8 @@ imports: version: 5174cc5c242a728b435ea2be8a2f7f998e15429b - name: github.com/jinzhu/inflection version: 74387dc39a75e970e7a3ae6a3386b5bd2e5c5cff +- name: github.com/jonboulle/clockwork + version: 3f831b65b61282ba6bece21b91beea2edc4c887a - name: github.com/julienschmidt/httprouter version: 8c199fb6259ffc1af525cc3ad52ee60ba8359669 - name: github.com/kylelemons/godebug diff --git a/glide.yaml b/glide.yaml index 96e81f9..6a99ea6 100644 --- a/glide.yaml +++ b/glide.yaml @@ -3,11 +3,11 @@ import: - package: github.com/sirupsen/logrus version: 1.0.3 - package: github.com/julienschmidt/httprouter - version: 1.1 + version: "1.1" - package: github.com/lib/pq version: go1.0-cutoff - package: github.com/jinzhu/gorm - version: 1.0 + version: "1.0" - package: github.com/satori/go.uuid version: 1.1.0 - package: github.com/emanoelxavier/openid2go @@ -20,3 +20,4 @@ import: version: d65d576e9348f5982d7f6d83682b694e731a45c6 - package: github.com/stretchr/testify version: 1.1.4 +- package: github.com/coreos/go-oidc From 2d5ec1e309dcb5edafc606392e88f7f9ed650289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Wed, 2 Nov 2016 10:10:10 +0100 Subject: [PATCH 06/18] Added role table --- demo/api/main.go | 1 + demo/docker/docker-compose.yml | 2 + demo/web/main.go | 71 ++++++++++++++++++++++++++++++++-- demo/web/tmpl/index.html | 18 ++++++++- scripts/test.sh | 2 +- 5 files changed, 88 insertions(+), 6 deletions(-) diff --git a/demo/api/main.go b/demo/api/main.go index 401a019..d4284c2 100644 --- a/demo/api/main.go +++ b/demo/api/main.go @@ -6,6 +6,7 @@ import ( "os" "bytes" + "github.com/Sirupsen/logrus" "github.com/julienschmidt/httprouter" ) diff --git a/demo/docker/docker-compose.yml b/demo/docker/docker-compose.yml index 941b150..b449eba 100644 --- a/demo/docker/docker-compose.yml +++ b/demo/docker/docker-compose.yml @@ -69,6 +69,8 @@ services: - APIPORT=8001 - WEBHOST=localhost - WEBPORT=8101 + - FOULKON_WORKER_HOST=foulkonworkercompose + - FOULKON_WORKER_PORT=8000 - OIDC_CLIENT_ID=953874647871-gco7i6urt1i4clafgoeuo2gnicj2sg2q.apps.googleusercontent.com - OIDC_CLIENT_SECRET=T2P-Q8hxq5jfdR5EhPFGuFVs - OIDC_IDP_DISCOVERY=https://accounts.google.com diff --git a/demo/web/main.go b/demo/web/main.go index bcb3e4f..986acca 100644 --- a/demo/web/main.go +++ b/demo/web/main.go @@ -16,6 +16,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/coreos/go-oidc/oidc" "github.com/julienschmidt/httprouter" + "time" ) // CONSTANTS @@ -26,6 +27,10 @@ const ( APIHOST = "APIHOST" APIPORT = "APIPORT" + // Foulkon + FOULKONHOST = "FOULKON_WORKER_HOST" + FOULKONPORT = "FOULKON_WORKER_PORT" + // OIDC OIDCCLIENTID = "OIDC_CLIENT_ID" OIDCCLIENTSECRET = "OIDC_CLIENT_SECRET" @@ -34,13 +39,14 @@ const ( type Node struct { // URLs - WebBaseUrl string - APIBaseUrl string + WebBaseUrl string + APIBaseUrl string + FoulkonBaseUrl string // Profile UserId string Token string - Roles []string + Roles []UserGroups // Table Resources ResourceTableElements *ResourceTableElements @@ -58,6 +64,19 @@ type Resource struct { Resource string `json:"resource, omitempty"` } +type UserGroups struct { + Org string `json:"org, omitempty"` + Name string `json:"name, omitempty"` + CreateAt time.Time `json:"joined, omitempty"` +} + +type GetGroupsByUserIdResponse struct { + Groups []UserGroups `json:"groups, omitempty"` + Limit int `json:"limit, omitempty"` + Offset int `json:"offset, omitempty"` + Total int `json:"total, omitempty"` +} + type UpdateResource struct { Resource string `json:"resource, omitempty"` } @@ -89,6 +108,11 @@ func main() { webURL := "http://" + host + ":" + port node.WebBaseUrl = webURL + // Get foulkon url + foulkonhost := os.Getenv(FOULKONHOST) + foulkonport := os.Getenv(FOULKONPORT) + node.FoulkonBaseUrl = "http://" + foulkonhost + ":" + foulkonport + "/api/v1" + logger = &logrus.Logger{ Out: os.Stdout, Formatter: &logrus.JSONFormatter{}, @@ -130,6 +154,47 @@ func main() { // HANDLERS func HandlePage(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { + if node.Token != "" { + request, err := http.NewRequest(http.MethodGet, node.FoulkonBaseUrl+"/users/"+node.UserId+"/groups", nil) + if err != nil { + logger.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + request.SetBasicAuth("admin", "admin") + + response, err := client.Do(request) + if err != nil { + logger.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer response.Body.Close() + if response.StatusCode != http.StatusOK { + err := mainTemplate.Execute(w, node) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + return + } + + buffer := new(bytes.Buffer) + if _, err := buffer.ReadFrom(response.Body); err != nil { + logger.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + res := new(GetGroupsByUserIdResponse) + if err := json.Unmarshal(buffer.Bytes(), &res); err != nil { + logger.Info(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + node.Roles = res.Groups + + } err := mainTemplate.Execute(w, node) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/demo/web/tmpl/index.html b/demo/web/tmpl/index.html index bb62eb5..2642d86 100644 --- a/demo/web/tmpl/index.html +++ b/demo/web/tmpl/index.html @@ -10,9 +10,23 @@ {{.UserId}} - Roles - EMPTY YET + Role + Organization + Joined + {{ $length := len .Roles }} {{ if eq $length 0 }} + + No roles yet + + {{else}} + {{range $element := .Roles}} + + {{ $element.Name }} + {{ $element.Org }} + {{ $element.CreateAt.Format "Jan 02, 2006 15:04:05 UTC" }} + + {{end}} + {{end}} {{end}}
diff --git a/scripts/test.sh b/scripts/test.sh index acd1c1c..0fa0c69 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -7,7 +7,7 @@ echo "" > coverage.txt echo "--> Running tests" echo -e '----> Running unit tests' -for d in $(go list ./... | grep -v '/vendor/' | egrep -v '/database/|cmd/|auth/oidc|foulkon/foulkon'); do +for d in $(go list ./... | grep -v '/vendor/' | egrep -v '/database/|demo/|cmd/|auth/oidc|foulkon/foulkon'); do go test -race -coverprofile=profile.out -covermode=atomic $d || exit 1 if [ -f profile.out ]; then cat profile.out >> coverage.txt From 6a2182161dcf38b9140770f9461076915831a844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Wed, 19 Oct 2016 10:40:32 +0200 Subject: [PATCH 07/18] Added docker-compose.yml --- scripts/docker/docker-compose.yml | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 scripts/docker/docker-compose.yml diff --git a/scripts/docker/docker-compose.yml b/scripts/docker/docker-compose.yml new file mode 100644 index 0000000..3c3e892 --- /dev/null +++ b/scripts/docker/docker-compose.yml @@ -0,0 +1,33 @@ +version: "2" +services: + postgrescompose: + image: "postgres:9.5" + container_name: "postgrescompose" + hostname: "postgrescompose" + ports: + - "5432:5432" + command: "postgres" + foulkonworkercompose: + image: "tecsisa/foulkon:v0.2.0" + container_name: "foulkonworkercompose" + hostname: "foulkonworkercompose" + environment: + - FOULKON_WORKER_HOST=foulkonworkercompose + - FOULKON_WORKER_PORT=8000 + - FOULKON_ADMIN_USER=admin + - FOULKON_ADMIN_PASS=admin + - FOULKON_WORKER_LOG_TYPE=default + - FOULKON_WORKER_LOG_LEVEL=info + - FOULKON_DB=postgres + - FOULKON_DB_POSTGRES_DS=postgres://postgres:password@postgrescompose:5432/postgres?sslmode=disable + - FOULKON_DB_POSTGRES_IDLECONNS=10 + - FOULKON_DB_POSTGRES_MAXCONNS=20 + - FOULKON_DB_POSTGRES_CONNTTL=300 + - FOULKON_AUTH_TYPE=oidc + - FOULKON_AUTH_ISSUER=https://accounts.google.com + - FOULKON_AUTH_CLIENTID=google-client-identity + ports: + - "8000:8000" + command: "worker" + depends_on: + - postgrescompose From 155f55e965277a1ed0aba9ce36c558d4b28507a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Fri, 21 Oct 2016 14:17:49 +0200 Subject: [PATCH 08/18] added demo folder --- demo/Dockerfile | 15 +++++++ demo/api/main.go | 4 +- demo/docker-compose.yml | 33 +++++++++++++++ demo/web/main.go | 23 +++++------ demo/web/tmpl/base/header.html | 73 ++++++++++++++++++++++------------ demo/web/tmpl/index.html | 66 ++++++++++++++++-------------- 6 files changed, 146 insertions(+), 68 deletions(-) create mode 100644 demo/Dockerfile create mode 100644 demo/docker-compose.yml diff --git a/demo/Dockerfile b/demo/Dockerfile new file mode 100644 index 0000000..e5e1b0f --- /dev/null +++ b/demo/Dockerfile @@ -0,0 +1,15 @@ +FROM alpine +MAINTAINER Tecsisa + +USER root +RUN apk update && apk add ca-certificates + +# API +COPY bin/demoapi /go/bin/demoapi + +# WEB +COPY bin/demoweb /go/bin/demoweb + +ENV PATH=$PATH:/go/bin + +EXPOSE 8000 8001 \ No newline at end of file diff --git a/demo/api/main.go b/demo/api/main.go index d4284c2..0d799e4 100644 --- a/demo/api/main.go +++ b/demo/api/main.go @@ -39,7 +39,7 @@ func HandleAddResource(w http.ResponseWriter, r *http.Request, _ httprouter.Para resources[request.Id] = request.Resource response = request } - processHttpResponse(w, response, err, http.StatusOK) + processHttpResponse(w, response, err, http.StatusCreated) } func HandleGetResource(w http.ResponseWriter, _ *http.Request, ps httprouter.Params) { @@ -271,4 +271,4 @@ func createRolesAndPolicies() { logger.Fatal(err) } -} +} \ No newline at end of file diff --git a/demo/docker-compose.yml b/demo/docker-compose.yml new file mode 100644 index 0000000..3c3e892 --- /dev/null +++ b/demo/docker-compose.yml @@ -0,0 +1,33 @@ +version: "2" +services: + postgrescompose: + image: "postgres:9.5" + container_name: "postgrescompose" + hostname: "postgrescompose" + ports: + - "5432:5432" + command: "postgres" + foulkonworkercompose: + image: "tecsisa/foulkon:v0.2.0" + container_name: "foulkonworkercompose" + hostname: "foulkonworkercompose" + environment: + - FOULKON_WORKER_HOST=foulkonworkercompose + - FOULKON_WORKER_PORT=8000 + - FOULKON_ADMIN_USER=admin + - FOULKON_ADMIN_PASS=admin + - FOULKON_WORKER_LOG_TYPE=default + - FOULKON_WORKER_LOG_LEVEL=info + - FOULKON_DB=postgres + - FOULKON_DB_POSTGRES_DS=postgres://postgres:password@postgrescompose:5432/postgres?sslmode=disable + - FOULKON_DB_POSTGRES_IDLECONNS=10 + - FOULKON_DB_POSTGRES_MAXCONNS=20 + - FOULKON_DB_POSTGRES_CONNTTL=300 + - FOULKON_AUTH_TYPE=oidc + - FOULKON_AUTH_ISSUER=https://accounts.google.com + - FOULKON_AUTH_CLIENTID=google-client-identity + ports: + - "8000:8000" + command: "worker" + depends_on: + - postgrescompose diff --git a/demo/web/main.go b/demo/web/main.go index 986acca..701c582 100644 --- a/demo/web/main.go +++ b/demo/web/main.go @@ -8,15 +8,14 @@ import ( "net/http" "os" - "strconv" - "fmt" "net/url" + "time" + "github.com/Sirupsen/logrus" "github.com/coreos/go-oidc/oidc" "github.com/julienschmidt/httprouter" - "time" ) // CONSTANTS @@ -45,6 +44,7 @@ type Node struct { // Profile UserId string + Email string Token string Roles []UserGroups @@ -280,16 +280,14 @@ func HandleAddResource(w http.ResponseWriter, r *http.Request, _ httprouter.Para http.Error(w, err.Error(), http.StatusInternalServerError) return } - if response.StatusCode != http.StatusOK { + + if response.StatusCode != http.StatusCreated { + renderErrorTemplate(w, response.StatusCode, fmt.Sprintf("Add method error. Error code: %v", http.StatusText(response.StatusCode))) return } - if response.StatusCode == http.StatusOK { - node.Message = "Resource created!" - } else { - node.Message = "Error, status code received " + strconv.Itoa(response.StatusCode) - } + node.Message = fmt.Sprintf("Resource with id %v and resource %v was created!", res.Id, res.Resource) addTemplate.Execute(w, node) } else { @@ -339,7 +337,7 @@ func HandleUpdateResource(w http.ResponseWriter, r *http.Request, _ httprouter.P return } - node.Message = "Resource Updated!" + node.Message = fmt.Sprintf("Resource with id %v was updated to resource %v!", id, res.Resource) updateTemplate.Execute(w, node) } else { node.Message = "" @@ -377,7 +375,7 @@ func HandleRemoveResource(w http.ResponseWriter, r *http.Request, _ httprouter.P return } - node.Message = "Resource deleted!" + node.Message = fmt.Sprintf("Resource with id %v was removed", id) removeTemplate.Execute(w, node) } else { node.Message = "" @@ -427,6 +425,7 @@ func HandleCallbackFunc(c *oidc.Client) httprouter.Handle { node.Token = tok.Encode() node.UserId, _, _ = claims.StringClaim("sub") + node.Email, _, _ = claims.StringClaim("email") http.Redirect(w, r, node.WebBaseUrl, http.StatusFound) } @@ -550,4 +549,4 @@ func renderErrorTemplate(w http.ResponseWriter, code int, msg string) { logger.Info(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) } -} +} \ No newline at end of file diff --git a/demo/web/tmpl/base/header.html b/demo/web/tmpl/base/header.html index 14d53e3..21b69b0 100644 --- a/demo/web/tmpl/base/header.html +++ b/demo/web/tmpl/base/header.html @@ -1,31 +1,54 @@ - - - - FOULKON - + + + + Foulkon demo + + + + + + + + + +
\ No newline at end of file diff --git a/demo/web/tmpl/index.html b/demo/web/tmpl/index.html index 2642d86..e68c58c 100644 --- a/demo/web/tmpl/index.html +++ b/demo/web/tmpl/index.html @@ -1,34 +1,42 @@ {{ template "header.html" }} - -
- {{if eq .Token ""}} - You must login before you use endpoints to work with example resources. Click here to log in. +

Foulkon Example Demo

+
+ {{if eq .Token ""}} + You must login before you use endpoints to work with example resources. Click here to log in. + {{else}} +
+
+ User identifier: + 123123213123123123321 +
+
+
+
+ Email: + {{.Email}} +
+
+ + + + + + + {{ $length := len .Roles }} {{ if eq $length 0 }} + + + {{else}} -
RoleOrganizationJoined
No roles yet
- - - - - - - - - - {{ $length := len .Roles }} {{ if eq $length 0 }} - - - - {{else}} - {{range $element := .Roles}} - - - - - - {{end}} - {{end}} -
User identifier{{.UserId}}
RoleOrganizationJoined
No roles yet
{{ $element.Name }}{{ $element.Org }}{{ $element.CreateAt.Format "Jan 02, 2006 15:04:05 UTC" }}
+ {{range $element := .Roles}} + + {{ $element.Name }} + {{ $element.Org }} + {{ $element.CreateAt.Format "Jan 02, 2006 15:04:05 UTC" }} + {{end}} -
+ {{end}} + + {{end}} +
{{ template "footer.html" }} \ No newline at end of file From 280ece22e459f74cb9ed41563dc3cc0352cccd32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerson=20Pozo=20Gonz=C3=A1lez?= Date: Tue, 25 Oct 2016 16:51:50 +0200 Subject: [PATCH 09/18] Implements web logic --- demo/web/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/demo/web/main.go b/demo/web/main.go index 701c582..c7ab58e 100644 --- a/demo/web/main.go +++ b/demo/web/main.go @@ -545,6 +545,7 @@ func renderErrorTemplate(w http.ResponseWriter, code int, msg string) { node.HttpErrorStatusCode = code node.ErrorMessage = msg err := errorTemplate.Execute(w, node) + if err != nil { logger.Info(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) From 54452b15f47c7bc493a1c67f9be1720004397644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Wed, 26 Oct 2016 15:43:41 +0200 Subject: [PATCH 10/18] Build demo script --- demo/Dockerfile | 15 -------------- demo/build-demo.sh | 3 +-- demo/docker-compose.yml | 33 ------------------------------- demo/docker/docker-compose.yml | 2 +- demo/web/main.go | 1 - scripts/docker/docker-compose.yml | 33 ------------------------------- 6 files changed, 2 insertions(+), 85 deletions(-) delete mode 100644 demo/Dockerfile delete mode 100644 demo/docker-compose.yml delete mode 100644 scripts/docker/docker-compose.yml diff --git a/demo/Dockerfile b/demo/Dockerfile deleted file mode 100644 index e5e1b0f..0000000 --- a/demo/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM alpine -MAINTAINER Tecsisa - -USER root -RUN apk update && apk add ca-certificates - -# API -COPY bin/demoapi /go/bin/demoapi - -# WEB -COPY bin/demoweb /go/bin/demoweb - -ENV PATH=$PATH:/go/bin - -EXPOSE 8000 8001 \ No newline at end of file diff --git a/demo/build-demo.sh b/demo/build-demo.sh index db9352a..344786b 100755 --- a/demo/build-demo.sh +++ b/demo/build-demo.sh @@ -16,5 +16,4 @@ echo "----> Building Docker demo images..." docker build -t tecsisa/foulkondemo -f demo/docker/Dockerfile . >/dev/null || exit 1 echo "----> Starting Docker Compose..." -docker-compose -f demo/docker/docker-compose.yml up --force-recreate --abort-on-container-exit - +docker-compose -f demo/docker/docker-compose.yml up --force-recreate --abort-on-container-exit \ No newline at end of file diff --git a/demo/docker-compose.yml b/demo/docker-compose.yml deleted file mode 100644 index 3c3e892..0000000 --- a/demo/docker-compose.yml +++ /dev/null @@ -1,33 +0,0 @@ -version: "2" -services: - postgrescompose: - image: "postgres:9.5" - container_name: "postgrescompose" - hostname: "postgrescompose" - ports: - - "5432:5432" - command: "postgres" - foulkonworkercompose: - image: "tecsisa/foulkon:v0.2.0" - container_name: "foulkonworkercompose" - hostname: "foulkonworkercompose" - environment: - - FOULKON_WORKER_HOST=foulkonworkercompose - - FOULKON_WORKER_PORT=8000 - - FOULKON_ADMIN_USER=admin - - FOULKON_ADMIN_PASS=admin - - FOULKON_WORKER_LOG_TYPE=default - - FOULKON_WORKER_LOG_LEVEL=info - - FOULKON_DB=postgres - - FOULKON_DB_POSTGRES_DS=postgres://postgres:password@postgrescompose:5432/postgres?sslmode=disable - - FOULKON_DB_POSTGRES_IDLECONNS=10 - - FOULKON_DB_POSTGRES_MAXCONNS=20 - - FOULKON_DB_POSTGRES_CONNTTL=300 - - FOULKON_AUTH_TYPE=oidc - - FOULKON_AUTH_ISSUER=https://accounts.google.com - - FOULKON_AUTH_CLIENTID=google-client-identity - ports: - - "8000:8000" - command: "worker" - depends_on: - - postgrescompose diff --git a/demo/docker/docker-compose.yml b/demo/docker/docker-compose.yml index b449eba..910d63d 100644 --- a/demo/docker/docker-compose.yml +++ b/demo/docker/docker-compose.yml @@ -79,4 +79,4 @@ services: command: "web" depends_on: - postgrescompose - - foulkonworkercompose + - foulkonworkercompose \ No newline at end of file diff --git a/demo/web/main.go b/demo/web/main.go index c7ab58e..701c582 100644 --- a/demo/web/main.go +++ b/demo/web/main.go @@ -545,7 +545,6 @@ func renderErrorTemplate(w http.ResponseWriter, code int, msg string) { node.HttpErrorStatusCode = code node.ErrorMessage = msg err := errorTemplate.Execute(w, node) - if err != nil { logger.Info(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/scripts/docker/docker-compose.yml b/scripts/docker/docker-compose.yml deleted file mode 100644 index 3c3e892..0000000 --- a/scripts/docker/docker-compose.yml +++ /dev/null @@ -1,33 +0,0 @@ -version: "2" -services: - postgrescompose: - image: "postgres:9.5" - container_name: "postgrescompose" - hostname: "postgrescompose" - ports: - - "5432:5432" - command: "postgres" - foulkonworkercompose: - image: "tecsisa/foulkon:v0.2.0" - container_name: "foulkonworkercompose" - hostname: "foulkonworkercompose" - environment: - - FOULKON_WORKER_HOST=foulkonworkercompose - - FOULKON_WORKER_PORT=8000 - - FOULKON_ADMIN_USER=admin - - FOULKON_ADMIN_PASS=admin - - FOULKON_WORKER_LOG_TYPE=default - - FOULKON_WORKER_LOG_LEVEL=info - - FOULKON_DB=postgres - - FOULKON_DB_POSTGRES_DS=postgres://postgres:password@postgrescompose:5432/postgres?sslmode=disable - - FOULKON_DB_POSTGRES_IDLECONNS=10 - - FOULKON_DB_POSTGRES_MAXCONNS=20 - - FOULKON_DB_POSTGRES_CONNTTL=300 - - FOULKON_AUTH_TYPE=oidc - - FOULKON_AUTH_ISSUER=https://accounts.google.com - - FOULKON_AUTH_CLIENTID=google-client-identity - ports: - - "8000:8000" - command: "worker" - depends_on: - - postgrescompose From 9a5558a7fd55e04ae758255f64a06ef49ae8fa6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Fri, 28 Oct 2016 09:58:39 +0200 Subject: [PATCH 11/18] updated templates and script to start with "make demo" --- demo/web/tmpl/base/header.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/web/tmpl/base/header.html b/demo/web/tmpl/base/header.html index 21b69b0..c50d6af 100644 --- a/demo/web/tmpl/base/header.html +++ b/demo/web/tmpl/base/header.html @@ -51,4 +51,4 @@
-
\ No newline at end of file +
From d202e5a186ef1094c4ff7f697dcde3db9c3a9e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Wed, 2 Nov 2016 10:10:10 +0100 Subject: [PATCH 12/18] Added role table --- demo/web/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/demo/web/main.go b/demo/web/main.go index 701c582..1129f67 100644 --- a/demo/web/main.go +++ b/demo/web/main.go @@ -16,6 +16,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/coreos/go-oidc/oidc" "github.com/julienschmidt/httprouter" + "time" ) // CONSTANTS From ad53cd75bd15e64b94416140fea11f34962bccf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Fri, 11 Nov 2016 11:31:36 +0100 Subject: [PATCH 13/18] cahnges messages info and added email data in homepage --- demo/web/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/demo/web/main.go b/demo/web/main.go index 1129f67..701c582 100644 --- a/demo/web/main.go +++ b/demo/web/main.go @@ -16,7 +16,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/coreos/go-oidc/oidc" "github.com/julienschmidt/httprouter" - "time" ) // CONSTANTS From 6cbd6f61d31e5726a780c45ae4cc72cc05905eea Mon Sep 17 00:00:00 2001 From: Miguel Cortecero Torres Date: Fri, 11 Nov 2016 12:43:19 +0100 Subject: [PATCH 14/18] Add Material Design styles and small logo to Foulkon Example Demo --- demo/web/tmpl/add.html | 36 +++++++------ demo/web/tmpl/base/footer.html | 3 ++ demo/web/tmpl/base/foulkon-logo.html | 1 + demo/web/tmpl/base/header.html | 80 ++++++++++++++-------------- demo/web/tmpl/delete.html | 30 +++++------ demo/web/tmpl/error.html | 13 ++--- demo/web/tmpl/list.html | 31 ++++++----- demo/web/tmpl/update.html | 35 ++++++------ 8 files changed, 123 insertions(+), 106 deletions(-) create mode 100644 demo/web/tmpl/base/foulkon-logo.html diff --git a/demo/web/tmpl/add.html b/demo/web/tmpl/add.html index 0a8c08b..d88f2f3 100644 --- a/demo/web/tmpl/add.html +++ b/demo/web/tmpl/add.html @@ -1,21 +1,23 @@ {{ template "header.html" }} -
-
- - - - - - - - -
IDResource
-
-
- -
- {{ .Message }} -
+

Add a resource

+
+
+
+ + +
+
+ + +
+
+ +
+
+
+
+ {{ .Message }} +
{{ template "footer.html" }} \ No newline at end of file diff --git a/demo/web/tmpl/base/footer.html b/demo/web/tmpl/base/footer.html index 5b6e2d6..40b7fef 100644 --- a/demo/web/tmpl/base/footer.html +++ b/demo/web/tmpl/base/footer.html @@ -1,3 +1,6 @@
+ + + diff --git a/demo/web/tmpl/base/foulkon-logo.html b/demo/web/tmpl/base/foulkon-logo.html new file mode 100644 index 0000000..dca34e3 --- /dev/null +++ b/demo/web/tmpl/base/foulkon-logo.html @@ -0,0 +1 @@ +data:image/png;base64,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 \ No newline at end of file diff --git a/demo/web/tmpl/base/header.html b/demo/web/tmpl/base/header.html index c50d6af..2b5592f 100644 --- a/demo/web/tmpl/base/header.html +++ b/demo/web/tmpl/base/header.html @@ -1,54 +1,54 @@ - - - Foulkon demo - - - - - + + + Foulkon demo + + + + +
diff --git a/demo/web/tmpl/delete.html b/demo/web/tmpl/delete.html index a01aea2..d1516c5 100644 --- a/demo/web/tmpl/delete.html +++ b/demo/web/tmpl/delete.html @@ -1,19 +1,19 @@ {{ template "header.html" }} -
-
- - - - - - -
ID
-
-
- -
- {{ .Message }} -
+

Remove a resource

+
+
+
+ + +
+
+ +
+
+
+
+ {{ .Message }} +
{{ template "footer.html" }} \ No newline at end of file diff --git a/demo/web/tmpl/error.html b/demo/web/tmpl/error.html index 93d41a4..fd73e54 100644 --- a/demo/web/tmpl/error.html +++ b/demo/web/tmpl/error.html @@ -1,10 +1,11 @@ {{ template "header.html" }} - -
- {{.HttpErrorStatusCode}} -
-
- {{.ErrorMessage}} +
+ + {{.HttpErrorStatusCode}} + + + {{.ErrorMessage}} +
{{ template "footer.html" }} \ No newline at end of file diff --git a/demo/web/tmpl/list.html b/demo/web/tmpl/list.html index 68ff28e..eb80714 100644 --- a/demo/web/tmpl/list.html +++ b/demo/web/tmpl/list.html @@ -1,23 +1,30 @@ {{ template "header.html" }} -
-

Resources

- {{ $length := len .ResourceTableElements.Resources }} {{ if eq $length 0 }} +
+

Resources

+ {{ $length := len .ResourceTableElements.Resources }} + {{ if eq $length 0 }} +
List empty - {{else}} - + + {{else}} +
+ + + {{range $element := .ResourceTableElements.Resources}} - - - - + + + + {{end}} -
ID Resource
{{ $element.Id }}{{ $element.Resource }}
{{ $element.Id }}{{ $element.Resource }}
- {{end}} -
+ + + {{end}} +
{{ template "footer.html" }} \ No newline at end of file diff --git a/demo/web/tmpl/update.html b/demo/web/tmpl/update.html index 9032723..571d86c 100644 --- a/demo/web/tmpl/update.html +++ b/demo/web/tmpl/update.html @@ -1,21 +1,24 @@ {{ template "header.html" }} -
-
- - - - - - - - -
IDNew resource
-
-
+

Update a resource

+
+
+
+ + +
+
+ + +
+
+ +
+
+
+
+ {{ .Message }} +
-
- {{ .Message }} -
{{ template "footer.html" }} \ No newline at end of file From fac31554f34d9c347946f77d48831bb38c91ac52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Thu, 1 Jun 2017 08:43:39 +0200 Subject: [PATCH 15/18] fmt code --- demo/api/main.go | 2 +- demo/web/main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/api/main.go b/demo/api/main.go index 0d799e4..feea2fc 100644 --- a/demo/api/main.go +++ b/demo/api/main.go @@ -271,4 +271,4 @@ func createRolesAndPolicies() { logger.Fatal(err) } -} \ No newline at end of file +} diff --git a/demo/web/main.go b/demo/web/main.go index 701c582..486c05a 100644 --- a/demo/web/main.go +++ b/demo/web/main.go @@ -549,4 +549,4 @@ func renderErrorTemplate(w http.ResponseWriter, code int, msg string) { logger.Info(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) } -} \ No newline at end of file +} From f9cc6f28d5e89b56bdfddf5057a3b4384097edb2 Mon Sep 17 00:00:00 2001 From: Ruben Date: Wed, 16 Aug 2017 21:52:58 +0200 Subject: [PATCH 16/18] started demo doc --- demo/README.md | 89 ++++++++++++++++++++++++++++++++++ demo/docker/Dockerfile | 2 +- demo/docker/docker-compose.yml | 17 ++++--- demo/tour.md | 3 ++ 4 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 demo/README.md create mode 100644 demo/tour.md diff --git a/demo/README.md b/demo/README.md new file mode 100644 index 0000000..85321eb --- /dev/null +++ b/demo/README.md @@ -0,0 +1,89 @@ +# Foulkon demo + +This demo shows how Foulkon works, and how to manage it. + +## Previous requirements + +To run this demo, you have to set some properties and system packages. + +### Go configuration + +We have to set next environment vars: + + - GOROOT + - GOPATH + - GOBIN + +On Ubuntu (Directory examples, you can choose your own directories): + +```bash + +export GOROOT=$HOME/dev/golang/go +export GOPATH=$HOME/dev/sources/golang +export GOBIN=$HOME/dev/sources/golang/bin + +``` + +This directories will be created before. Also, the GOBIN environment variable +will be in your execution path. + +### System packages + +This demo works with Docker, so you have to install Docker and Docker Compose. + + - [Docker installation doc](https://docs.docker.com/engine/installation/) + - [Docker Compose installation doc](https://docs.docker.com/compose/install/) + +## Start Demo + +First, you have to download Foulkon project: + +```bash + +go get github.com/Tecsisa/foulkon + +``` + +Second, go to Foulkon directory: + +```bash + +cd $GOPATH/src/github.com/Tecsisa/foulkon + +``` + +Third, execute next command to get all dependencies: + +```bash + +make bootstrap + +``` + +User login needs a Google client to make UI able to get a user. +To do this, follow the [Google guide](https://developers.google.com/identity/protocols/OpenIDConnect) to get a Google client +set http://localhost:8101/callback in your Authorized redirect URIs, and change next properties in [Docker-compose file](docker/docker-compose.yml): + + - In foulkonworkercompose: + - FOULKON_AUTH_CLIENTID for your client id. + - In foulkondemowebcompose: + - OIDC_CLIENT_ID for your client id. + - OIDC_CLIENT_SECRET for your secret. + +Finally, execute demo command to start demo: + +```bash + +make bootstrap + +``` + +The applications started are next: + + - Worker: Started on http://localhost:8000 + - Proxy: Started on http://localhost:8001 + - API demo: Started on http://localhost:8100 + - UI demo: Started on http://localhost:8101 + +Now, you have all suite to try Foulkon, go to [Tour](tour.md) to see an example. + diff --git a/demo/docker/Dockerfile b/demo/docker/Dockerfile index 39e55de..3b25cfb 100644 --- a/demo/docker/Dockerfile +++ b/demo/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM tecsisa/foulkon:v0.2.0 +FROM tecsisa/foulkon:v0.3.0 MAINTAINER Tecsisa # Copy resources of this API diff --git a/demo/docker/docker-compose.yml b/demo/docker/docker-compose.yml index 910d63d..f677070 100644 --- a/demo/docker/docker-compose.yml +++ b/demo/docker/docker-compose.yml @@ -6,7 +6,7 @@ services: hostname: "postgrescompose" command: "postgres" foulkonworkercompose: - image: "tecsisa/foulkon:v0.2.0" + image: "tecsisa/foulkon:v0.3.0" container_name: "foulkonworkercompose" hostname: "foulkonworkercompose" environment: @@ -23,14 +23,14 @@ services: - FOULKON_DB_POSTGRES_CONNTTL=300 - FOULKON_AUTH_TYPE=oidc - FOULKON_AUTH_ISSUER=https://accounts.google.com - - FOULKON_AUTH_CLIENTID=953874647871-gco7i6urt1i4clafgoeuo2gnicj2sg2q.apps.googleusercontent.com + - FOULKON_AUTH_CLIENTID=GoogleClientId ports: - "8000:8000" command: "worker" depends_on: - postgrescompose foulkondemoproxycompose: - image: "tecsisa/foulkondemo:latest" + image: "tecsisa/foulkon:v0.3.0" container_name: "foulkondemoproxycompose" hostname: "foulkondemoproxycompose" environment: @@ -39,6 +39,11 @@ services: - FOULKON_PROXY_LOG_TYPE=default - FOULKON_PROXY_LOG_LEVEL=info - FOULKON_WORKER_URL=http://foulkonworkercompose:8000 + - FOULKON_DB=postgres + - FOULKON_DB_POSTGRES_DS=postgres://postgres:password@postgrescompose:5432/postgres?sslmode=disable + - FOULKON_DB_POSTGRES_IDLECONNS=10 + - FOULKON_DB_POSTGRES_MAXCONNS=20 + - FOULKON_DB_POSTGRES_CONNTTL=300 ports: - "8001:8001" command: "proxy" @@ -46,7 +51,7 @@ services: - postgrescompose - foulkonworkercompose foulkondemoapicompose: - image: "tecsisa/foulkondemo:latest" + image: "tecsisa/foulkondemo" container_name: "foulkondemoapicompose" hostname: "foulkondemoapicompose" environment: @@ -71,8 +76,8 @@ services: - WEBPORT=8101 - FOULKON_WORKER_HOST=foulkonworkercompose - FOULKON_WORKER_PORT=8000 - - OIDC_CLIENT_ID=953874647871-gco7i6urt1i4clafgoeuo2gnicj2sg2q.apps.googleusercontent.com - - OIDC_CLIENT_SECRET=T2P-Q8hxq5jfdR5EhPFGuFVs + - OIDC_CLIENT_ID=GoogleClientId + - OIDC_CLIENT_SECRET=GoogleClientSecret - OIDC_IDP_DISCOVERY=https://accounts.google.com ports: - "8101:8101" diff --git a/demo/tour.md b/demo/tour.md new file mode 100644 index 0000000..e213551 --- /dev/null +++ b/demo/tour.md @@ -0,0 +1,3 @@ +# Foulkon tour + +WIP \ No newline at end of file From 6ee84633b1958d7db896c9cf73033c6434c37495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Soleto=20Buenvar=C3=B3n?= Date: Mon, 25 Sep 2017 18:31:53 +0200 Subject: [PATCH 17/18] updated version --- demo/api/main.go | 2 +- demo/docker/docker-compose.yml | 7 +++---- demo/web/main.go | 2 +- glide.lock | 33 ++++++++++++--------------------- glide.yaml | 7 ++++--- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/demo/api/main.go b/demo/api/main.go index feea2fc..fa394ba 100644 --- a/demo/api/main.go +++ b/demo/api/main.go @@ -7,8 +7,8 @@ import ( "bytes" - "github.com/Sirupsen/logrus" "github.com/julienschmidt/httprouter" + "github.com/sirupsen/logrus" ) // CONSTANTS diff --git a/demo/docker/docker-compose.yml b/demo/docker/docker-compose.yml index f677070..79201b0 100644 --- a/demo/docker/docker-compose.yml +++ b/demo/docker/docker-compose.yml @@ -6,7 +6,7 @@ services: hostname: "postgrescompose" command: "postgres" foulkonworkercompose: - image: "tecsisa/foulkon:v0.3.0" + image: "tecsisa/foulkon:v0.4.0" container_name: "foulkonworkercompose" hostname: "foulkonworkercompose" environment: @@ -22,15 +22,13 @@ services: - FOULKON_DB_POSTGRES_MAXCONNS=20 - FOULKON_DB_POSTGRES_CONNTTL=300 - FOULKON_AUTH_TYPE=oidc - - FOULKON_AUTH_ISSUER=https://accounts.google.com - - FOULKON_AUTH_CLIENTID=GoogleClientId ports: - "8000:8000" command: "worker" depends_on: - postgrescompose foulkondemoproxycompose: - image: "tecsisa/foulkon:v0.3.0" + image: "tecsisa/foulkon:v0.4.0" container_name: "foulkondemoproxycompose" hostname: "foulkondemoproxycompose" environment: @@ -44,6 +42,7 @@ services: - FOULKON_DB_POSTGRES_IDLECONNS=10 - FOULKON_DB_POSTGRES_MAXCONNS=20 - FOULKON_DB_POSTGRES_CONNTTL=300 + - FOULKON_RESOURCES_REFRESH=10s ports: - "8001:8001" command: "proxy" diff --git a/demo/web/main.go b/demo/web/main.go index 486c05a..9a43908 100644 --- a/demo/web/main.go +++ b/demo/web/main.go @@ -13,9 +13,9 @@ import ( "time" - "github.com/Sirupsen/logrus" "github.com/coreos/go-oidc/oidc" "github.com/julienschmidt/httprouter" + "github.com/sirupsen/logrus" ) // CONSTANTS diff --git a/glide.lock b/glide.lock index 2628ef7..b03ba99 100644 --- a/glide.lock +++ b/glide.lock @@ -1,17 +1,8 @@ -<<<<<<< HEAD -hash: 93d9eba9da07ecb1e8de03b355a36f05d853193e3107852c68713fd7aac5fd3c -updated: 2017-09-04T10:16:05.262507613+02:00 -======= -hash: f982b82d1f05b3ba8a0157938c1b843fbc0226b7adb6e78f3f00f806cd26f88c -updated: 2016-10-27T12:24:03.814586358+02:00 ->>>>>>> updated templates and script to start with "make demo" +hash: c1aade463908be588aa9570dba8584c95269d410cd753f34729a75fd19f153cc +updated: 2018-02-05T15:54:15.97488+01:00 imports: -- name: github.com/coreos/dex - version: 4b9bdf163db85373f3ea59bb227dec445c618cbf - subpackages: - - pkg/log - name: github.com/coreos/go-oidc - version: 9fae754a41cbdc3be9cb97a180eb323b625db614 + version: a93f71fdfe73d2c0f5413c0565eea0af6523a6df subpackages: - http - jose @@ -19,14 +10,13 @@ imports: - oauth2 - oidc - name: github.com/coreos/pkg - version: fa94270d4bac0d8ae5dc6b71894e251aada93f74 + version: 97fdf19511ea361ae1c100dd393cc47f8dcfa1e1 subpackages: - - flagutil - health - httputil - timeutil - name: github.com/dgrijalva/jwt-go - version: 24c63f56522a87ec5339cc3567883f1039378fdb + version: dbeaa9332f19a944acb5736b4456cfcc02140e29 - name: github.com/emanoelxavier/openid2go version: efe3c34772c5a961048a05e9483da2bd24debed0 subpackages: @@ -34,9 +24,9 @@ imports: - name: github.com/jinzhu/gorm version: 5174cc5c242a728b435ea2be8a2f7f998e15429b - name: github.com/jinzhu/inflection - version: 74387dc39a75e970e7a3ae6a3386b5bd2e5c5cff + version: 1c35d901db3da928c72a72d8458480cc9ade058f - name: github.com/jonboulle/clockwork - version: 3f831b65b61282ba6bece21b91beea2edc4c887a + version: bcac9884e7502bb2b474c0339d889cb981a2f27f - name: github.com/julienschmidt/httprouter version: 8c199fb6259ffc1af525cc3ad52ee60ba8359669 - name: github.com/kylelemons/godebug @@ -55,11 +45,11 @@ imports: - name: github.com/satori/go.uuid version: 879c5887cd475cd7864858769793b2ceb0d44feb - name: github.com/sirupsen/logrus - version: f006c2ac4710855cf0f916dd6b77acf6b048dc6e + version: d682213848ed68c0a260ca37d6dd5ace8423f5ba subpackages: - hooks/test - name: github.com/square/go-jose - version: 789a4c4bd4c118f7564954f441b29c153ccd6a96 + version: 0210e50945bbf0685c3313c71cd243f0870b96e3 subpackages: - cipher - json @@ -68,13 +58,14 @@ imports: subpackages: - assert - name: golang.org/x/crypto - version: 1fbbd62cfec66bd39d91e97749579579d4d3037e + version: 1875d0a70c90e57f11972aefd42276df65e895b9 subpackages: - ssh/terminal - name: golang.org/x/sys - version: c200b10b5d5e122be351b67af224adc6128af5bf + version: 37707fdb30a5b38865cfb95e5aab41707daec7fd subpackages: - unix + - windows testImports: - name: github.com/davecgh/go-spew version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 diff --git a/glide.yaml b/glide.yaml index 6a99ea6..e8e7cb7 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,13 +1,13 @@ package: github.com/Tecsisa/foulkon import: - package: github.com/sirupsen/logrus - version: 1.0.3 + version: 1.0.4 - package: github.com/julienschmidt/httprouter - version: "1.1" + version: 1.1 - package: github.com/lib/pq version: go1.0-cutoff - package: github.com/jinzhu/gorm - version: "1.0" + version: 1.0 - package: github.com/satori/go.uuid version: 1.1.0 - package: github.com/emanoelxavier/openid2go @@ -21,3 +21,4 @@ import: - package: github.com/stretchr/testify version: 1.1.4 - package: github.com/coreos/go-oidc + version: a93f71fdfe73d2c0f5413c0565eea0af6523a6df From 7f3f80a7f37ca3387b7639667b6cc261fe3efcd5 Mon Sep 17 00:00:00 2001 From: Ruben Soleto Date: Mon, 9 Apr 2018 09:19:38 +0200 Subject: [PATCH 18/18] changed dist --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 594d429..b9af00a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ sudo: required -dist: xenial services: - docker