From 7df11d017d5a7ac0ba94dd82f51928a8cf92e4cf Mon Sep 17 00:00:00 2001 From: Andrea Fazzi Date: Thu, 2 Jan 2020 09:48:20 +0100 Subject: [PATCH] Protect API handler with role filters --- client/#client.go# | 117 +++++++++++++++++++++++++++++++++++++++++++ client/.#client.go | 1 + client/client.go | 117 +++++++++++++++++++++++++++++++++++++++++++ handlers/handlers.go | 12 ++++- 4 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 client/#client.go# create mode 120000 client/.#client.go create mode 100644 client/client.go diff --git a/client/#client.go# b/client/#client.go# new file mode 100644 index 00000000..e95bdc5d --- /dev/null +++ b/client/#client.go# @@ -0,0 +1,117 @@ +package client + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strconv" + + "git.andreafazzi.eu/andrea/oef/orm" + "git.andreafazzi.eu/andrea/oef/renderer" +) + +// A client represents a client connection to the Headmaster test +// server. +type Client struct { + Url *url.URL + Username string + Password string + User string + + token string +} + +// Dial connects to a test server instance at the specified address +// using the given credentials. +func Dial(host, username, password string) (*Client, error) { + url, err := url.Parse(host) + if err != nil { + return nil, err + } + + client := &Client{ + Url: url, + Username: username, + Password: password, + } + + response, err := client.SendRequest("GET", "get_token", nil) + if err != nil { + panic(err) + } + + var data struct { + Token string + User string + } + if err := json.Unmarshal(response, &data); err != nil { + panic(err) + } + client.token = data.Token + client.User = data.User + + return client, nil +} + +func (c *Client) SendRequest(method string, path string, data []byte) ([]byte, error) { + // Create the https request + + folderUrl, err := url.Parse(path) + if err != nil { + return nil, err + } + + client := &http.Client{} + req, err := http.NewRequest(method, c.Url.ResolveReference(folderUrl).String(), bytes.NewReader(data)) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/json") + req.SetBasicAuth(c.Username, c.Password) + + if c.token != "" { + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.token)) + } + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return body, nil +} + +func (c *Client) GetContests() ([]*orm.Teacher, error) { + var ( + response renderer.JsonResponse + teachers []*orm.Teacher + ) + + data, err := c.SendRequest("GET", "/api/teachers?format=json", nil) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(data, &response); err != nil { + return nil, err + } + + if string(response.Error) != "" { + return nil, errors.New(string(response.Error)) + } + + if err := json.Unmarshal(response.Result, &teachers); err != nil { + return nil, err + } + return teachers, nil +} diff --git a/client/.#client.go b/client/.#client.go new file mode 120000 index 00000000..1a20c017 --- /dev/null +++ b/client/.#client.go @@ -0,0 +1 @@ +andrea@aspire-E5-571.12528:1577436684 \ No newline at end of file diff --git a/client/client.go b/client/client.go new file mode 100644 index 00000000..0147c422 --- /dev/null +++ b/client/client.go @@ -0,0 +1,117 @@ +package client + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strconv" + + "git.andreafazzi.eu/andrea/oef/orm" + "git.andreafazzi.eu/andrea/oef/renderer" +) + +// A client represents a client connection to the Headmaster test +// server. +type Client struct { + Url *url.URL + Username string + Password string + User string + + token string +} + +// Dial connects to a test server instance at the specified address +// using the given credentials. +func Dial(host, username, password string) (*Client, error) { + url, err := url.Parse(host) + if err != nil { + return nil, err + } + + client := &Client{ + Url: url, + Username: username, + Password: password, + } + + response, err := client.SendRequest("GET", "get_token", nil) + if err != nil { + panic(err) + } + + var data struct { + Token string + User string + } + if err := json.Unmarshal(response, &data); err != nil { + panic(err) + } + client.token = data.Token + client.User = data.User + + return client, nil +} + +func (c *Client) SendRequest(method string, path string, data []byte) ([]byte, error) { + // Create the https request + + folderUrl, err := url.Parse(path) + if err != nil { + return nil, err + } + + client := &http.Client{} + req, err := http.NewRequest(method, c.Url.ResolveReference(folderUrl).String(), bytes.NewReader(data)) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/json") + req.SetBasicAuth(c.Username, c.Password) + + if c.token != "" { + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.token)) + } + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return body, nil +} + +func (c *Client) GetTeachers() ([]*orm.Teacher, error) { + var ( + response renderer.JsonResponse + teachers []*orm.Teacher + ) + + data, err := c.SendRequest("GET", "/api/teachers?format=json", nil) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(data, &response); err != nil { + return nil, err + } + + if string(response.Error) != "" { + return nil, errors.New(string(response.Error)) + } + + if err := json.Unmarshal(response.Result, &teachers); err != nil { + return nil, err + } + return teachers, nil +} diff --git a/handlers/handlers.go b/handlers/handlers.go index 0afbdeec..c381d1f6 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -111,7 +111,7 @@ func generateHandler(r *mux.Router, model interface{}) { )))).Methods(pattern.Methods...) } - // Set permissions + // Set permissions for HTML patterns for role, modelPermissions := range RolePermissions { for m, perm := range modelPermissions { @@ -125,6 +125,16 @@ func generateHandler(r *mux.Router, model interface{}) { permissions[role][pattern.Path(pluralizedModelName(model))] = true } } + + for _, pattern := range apiPatterns { + if pattern.Permission == p { + if permissions[role] == nil { + permissions[role] = make(map[string]bool) + } + permissions[role][pattern.Path(pluralizedModelName(model))] = true + } + } + } } }