auth
auth/client/client.go
Add kubernetes definitions. Define a replication controller that will spin up authd servers (using Ducky right now--other instances should rename the ducky parts appropriately). Also, my understanding of which labels go where may be shaky, which is probably evidenced by the fact that all of these things share the same lables. _Whatever_. It also hooks the generated pods up to the JWT secret volume, so they can properly read the JWT secret. Also, created a LoadBalancer Service that will route traffic to the pods created by the Replication Controller.
| 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 } |