auth
auth/client/client.go
Send events when logins are verified. Add an ActionLoginVerified constant to use as the action when a login has been verified. On second thought, this should probably just be "verified", huh? Then we can reuse it across models. Oops. We also added a call to send a login verified event to NSQ when the login is verified.
| paddy@172 | 1 package client |
| paddy@172 | 2 |
| paddy@172 | 3 import ( |
| paddy@172 | 4 "bytes" |
| paddy@172 | 5 "encoding/json" |
| paddy@172 | 6 "errors" |
| paddy@172 | 7 "io" |
| paddy@172 | 8 "net/http" |
| paddy@172 | 9 "strings" |
| paddy@173 | 10 "time" |
| paddy@172 | 11 |
| paddy@172 | 12 "code.secondbit.org/auth.hg" |
| paddy@173 | 13 "code.secondbit.org/uuid.hg" |
| paddy@172 | 14 ) |
| paddy@172 | 15 |
| paddy@172 | 16 var ( |
| paddy@172 | 17 ErrNilClient = errors.New("nil client wrapper") |
| paddy@172 | 18 ErrNilHTTPClient = errors.New("nil client") |
| paddy@172 | 19 ) |
| paddy@172 | 20 |
| paddy@172 | 21 type Client struct { |
| paddy@172 | 22 client *http.Client |
| paddy@172 | 23 address string |
| paddy@173 | 24 ID uuid.ID |
| paddy@172 | 25 } |
| paddy@172 | 26 |
| paddy@173 | 27 func New(address string, id uuid.ID) *Client { |
| paddy@172 | 28 address = strings.TrimRight(address, "/") |
| paddy@172 | 29 return &Client{ |
| paddy@172 | 30 address: address, |
| paddy@172 | 31 client: &http.Client{}, |
| paddy@173 | 32 ID: id, |
| paddy@172 | 33 } |
| paddy@172 | 34 } |
| paddy@172 | 35 |
| paddy@173 | 36 func (c *Client) do(method, url string, request interface{}, scopes []string, subject uuid.ID) (auth.Response, error) { |
| paddy@172 | 37 if c == nil { |
| paddy@172 | 38 return auth.Response{}, ErrNilClient |
| paddy@172 | 39 } |
| paddy@172 | 40 if c.client == nil { |
| paddy@172 | 41 return auth.Response{}, ErrNilHTTPClient |
| paddy@172 | 42 } |
| paddy@172 | 43 var response auth.Response |
| paddy@172 | 44 if !strings.HasPrefix(url, "http") { |
| paddy@172 | 45 url = strings.TrimLeft(url, "/") |
| paddy@172 | 46 url = "/" + url |
| paddy@172 | 47 url = c.address + url |
| paddy@172 | 48 } |
| paddy@172 | 49 var body io.Reader |
| paddy@172 | 50 if request != nil { |
| paddy@172 | 51 data, err := json.Marshal(request) |
| paddy@172 | 52 if err != nil { |
| paddy@172 | 53 return response, err |
| paddy@172 | 54 } |
| paddy@172 | 55 body = bytes.NewBuffer(data) |
| paddy@172 | 56 } |
| paddy@172 | 57 req, err := http.NewRequest(method, url, body) |
| paddy@172 | 58 if err != nil { |
| paddy@172 | 59 return response, err |
| paddy@172 | 60 } |
| paddy@173 | 61 req.Header.Set("Ducky-Scope", strings.Join(scopes, " ")) |
| paddy@173 | 62 req.Header.Set("Ducky-Issuer", c.ID.String()) |
| paddy@173 | 63 if subject != nil { |
| paddy@173 | 64 req.Header.Set("Ducky-Subject", subject.String()) |
| paddy@173 | 65 } |
| paddy@173 | 66 req.Header.Set("Ducky-Expires", time.Now().Add(time.Hour).String()) |
| paddy@173 | 67 req.Header.Set("Ducky-Issued-At", time.Now().String()) |
| paddy@173 | 68 req.Header.Set("Ducky-Not-Before", time.Now().Add(-5*time.Minute).String()) |
| paddy@172 | 69 resp, err := c.client.Do(req) |
| paddy@172 | 70 if err != nil { |
| paddy@172 | 71 return response, err |
| paddy@172 | 72 } |
| paddy@172 | 73 defer resp.Body.Close() |
| paddy@172 | 74 switch resp.Header.Get("Content-Type") { |
| paddy@172 | 75 case "application/json": |
| paddy@172 | 76 dec := json.NewDecoder(resp.Body) |
| paddy@172 | 77 err = dec.Decode(&response) |
| paddy@172 | 78 if err != nil { |
| paddy@172 | 79 return response, err |
| paddy@172 | 80 } |
| paddy@172 | 81 default: |
| paddy@172 | 82 dec := json.NewDecoder(resp.Body) |
| paddy@172 | 83 err = dec.Decode(&response) |
| paddy@172 | 84 if err != nil { |
| paddy@172 | 85 return response, err |
| paddy@172 | 86 } |
| paddy@172 | 87 } |
| paddy@172 | 88 return response, nil |
| paddy@172 | 89 } |
| paddy@172 | 90 |
| paddy@173 | 91 func (c *Client) Get(url string, scopes []string, subject uuid.ID) (auth.Response, error) { |
| paddy@173 | 92 return c.do("GET", url, nil, scopes, subject) |
| paddy@172 | 93 } |