auth

Paddy 2014-12-07 Parent:4cb65cf90217

85:1dc4e152e3b0 Go to Latest

auth/grant.go

Break client verification out, break token returns out. Break client verification out into a helper function to avoid rewriting it for pretty much every grant. Break token returns out into a new function as part of the GrantType, so that implicit grants can redirect with the token value. Split returning the token as JSON into its own exported function, which can be used in multiple grants. Return more relevant information to the template when a user is deciding whether or not to authorize a grant.

History
1 package auth
3 import (
4 "encoding/json"
5 "errors"
6 "net/http"
7 "time"
9 "code.secondbit.org/uuid"
10 )
12 func init() {
13 RegisterGrantType("authorization_code", GrantType{
14 Validate: authCodeGrantValidate,
15 IssuesRefresh: true,
16 ReturnToken: RenderJSONToken,
17 })
18 }
20 var (
21 // ErrNoGrantStore is returned when a Context tries to act on a grantStore without setting one first.
22 ErrNoGrantStore = errors.New("no grantStore was specified for the Context")
23 // ErrGrantNotFound is returned when a Grant is requested but not found in the grantStore.
24 ErrGrantNotFound = errors.New("grant not found in grantStore")
25 // ErrGrantAlreadyExists is returned when a Grant is added to a grantStore, but another Grant with the
26 // same Code already exists in the grantStore.
27 ErrGrantAlreadyExists = errors.New("grant already exists in grantStore")
28 )
30 // Grant represents an authorization grant made by a user to a Client, to
31 // access user data within a defined Scope for a limited amount of time.
32 type Grant struct {
33 Code string
34 Created time.Time
35 ExpiresIn int32
36 ClientID uuid.ID
37 Scope string
38 RedirectURI string
39 State string
40 ProfileID uuid.ID
41 }
43 type grantStore interface {
44 getGrant(code string) (Grant, error)
45 saveGrant(grant Grant) error
46 deleteGrant(code string) error
47 }
49 func (m *memstore) getGrant(code string) (Grant, error) {
50 m.grantLock.RLock()
51 defer m.grantLock.RUnlock()
52 grant, ok := m.grants[code]
53 if !ok {
54 return Grant{}, ErrGrantNotFound
55 }
56 return grant, nil
57 }
59 func (m *memstore) saveGrant(grant Grant) error {
60 m.grantLock.Lock()
61 defer m.grantLock.Unlock()
62 _, ok := m.grants[grant.Code]
63 if ok {
64 return ErrGrantAlreadyExists
65 }
66 m.grants[grant.Code] = grant
67 return nil
68 }
70 func (m *memstore) deleteGrant(code string) error {
71 m.grantLock.Lock()
72 defer m.grantLock.Unlock()
73 _, ok := m.grants[code]
74 if !ok {
75 return ErrGrantNotFound
76 }
77 delete(m.grants, code)
78 return nil
79 }
81 func authCodeGrantValidate(w http.ResponseWriter, r *http.Request, context Context) (scope string, profileID uuid.ID, valid bool) {
82 enc := json.NewEncoder(w)
83 code := r.PostFormValue("code")
84 if code == "" {
85 w.WriteHeader(http.StatusBadRequest)
86 renderJSONError(enc, "invalid_request")
87 return
88 }
89 clientID, success := verifyClient(w, r, true, context)
90 if !success {
91 return
92 }
93 grant, err := context.GetGrant(code)
94 if err != nil {
95 if err == ErrGrantNotFound {
96 w.WriteHeader(http.StatusBadRequest)
97 renderJSONError(enc, "invalid_grant")
98 return
99 }
100 w.WriteHeader(http.StatusInternalServerError)
101 renderJSONError(enc, "server_error")
102 return
103 }
104 redirectURI := r.PostFormValue("redirect_uri")
105 if grant.RedirectURI != redirectURI {
106 w.WriteHeader(http.StatusBadRequest)
107 renderJSONError(enc, "invalid_grant")
108 return
109 }
110 if !grant.ClientID.Equal(clientID) {
111 w.WriteHeader(http.StatusBadRequest)
112 renderJSONError(enc, "invalid_grant")
113 return
114 }
115 return grant.Scope, grant.ProfileID, true
116 }