auth

Paddy 2015-05-17 Parent:8ecb60d29b0d Child:4b68bac597b7

173:b0d1b3e39fc8 Go to Latest

auth/client/client.go

Make client use our auth(n/z) scheme. Our auth(n/z) scheme can be loosely defined as "encrypted tokens that nginx transforms into headers" and "scopes for bypassing ACL". Our Go client, which is what we'll be using to have services communicate with each other, follows this paradigm now by auto-injecting the headers we'll need to identify ourselves. This will work behind our firewall, but will be useless for the rest of the world, which will need to go through the nginx bastion that can strip the headers and replace them with the headers appropriate to the token attached to the request. This did involve setting a static client ID as the client for our email_verification listener. Ideally, this would cause Client registration (using that ID) when the listener starts up, ignoring ErrClientAlreadyExists. I don't want to have to write the code that will allow us to bypass the Client ACL properly right now, though, so we're just going to have to remember to manually create that Client. Or not. I don't think it will do any harm (outside the OAuth flow) to be using a Client ID that doesn't actually point to a Client. I just think it'd be good for record-keeping purposes.

History
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 }