auth

Paddy 2015-03-07 Parent:d30a3a12d387 Child:2809016184f6

141:a8e6122bfc1a Go to Latest

auth/authcode.go

Require authentication to update Clients. Require the Client's owner to supply basic authentication when updating a client.

History
1 package auth
3 import (
4 "encoding/json"
5 "errors"
6 "net/http"
7 "time"
9 "code.secondbit.org/uuid.hg"
10 )
12 func init() {
13 RegisterGrantType("authorization_code", GrantType{
14 Validate: authCodeGrantValidate,
15 Invalidate: authCodeGrantInvalidate,
16 IssuesRefresh: true,
17 ReturnToken: RenderJSONToken,
18 AllowsPublic: true,
19 AuditString: authCodeGrantAuditString,
20 })
21 }
23 var (
24 // ErrNoAuthorizationCodeStore is returned when a Context tries to act on a authorizationCodeStore without setting one first.
25 ErrNoAuthorizationCodeStore = errors.New("no authorizationCodeStore was specified for the Context")
26 // ErrAuthorizationCodeNotFound is returned when an AuthorizationCode is requested but not found in the authorizationCodeStore.
27 ErrAuthorizationCodeNotFound = errors.New("authorization code not found in authorizationCodeStore")
28 // ErrAuthorizationCodeAlreadyExists is returned when an AuthorizationCode is added to a authorizationCodeStore, but another AuthorizationCode with the
29 // same Code already exists in the authorizationCodeStore.
30 ErrAuthorizationCodeAlreadyExists = errors.New("authorization code already exists in authorizationCodeStore")
31 )
33 // AuthorizationCode represents an authorization grant made by a user to a Client, to
34 // access user data within a defined Scope for a limited amount of time.
35 type AuthorizationCode struct {
36 Code string
37 Created time.Time
38 ExpiresIn int32
39 ClientID uuid.ID
40 Scopes []string
41 RedirectURI string
42 State string
43 ProfileID uuid.ID
44 Used bool
45 }
47 type authorizationCodeStore interface {
48 getAuthorizationCode(code string) (AuthorizationCode, error)
49 saveAuthorizationCode(authCode AuthorizationCode) error
50 deleteAuthorizationCode(code string) error
51 useAuthorizationCode(code string) error
52 }
54 func (m *memstore) getAuthorizationCode(code string) (AuthorizationCode, error) {
55 m.authCodeLock.RLock()
56 defer m.authCodeLock.RUnlock()
57 authCode, ok := m.authCodes[code]
58 if !ok {
59 return AuthorizationCode{}, ErrAuthorizationCodeNotFound
60 }
61 return authCode, nil
62 }
64 func (m *memstore) saveAuthorizationCode(authCode AuthorizationCode) error {
65 m.authCodeLock.Lock()
66 defer m.authCodeLock.Unlock()
67 _, ok := m.authCodes[authCode.Code]
68 if ok {
69 return ErrAuthorizationCodeAlreadyExists
70 }
71 m.authCodes[authCode.Code] = authCode
72 return nil
73 }
75 func (m *memstore) deleteAuthorizationCode(code string) error {
76 m.authCodeLock.Lock()
77 defer m.authCodeLock.Unlock()
78 _, ok := m.authCodes[code]
79 if !ok {
80 return ErrAuthorizationCodeNotFound
81 }
82 delete(m.authCodes, code)
83 return nil
84 }
86 func (m *memstore) useAuthorizationCode(code string) error {
87 m.authCodeLock.Lock()
88 defer m.authCodeLock.Unlock()
89 a, ok := m.authCodes[code]
90 if !ok {
91 return ErrAuthorizationCodeNotFound
92 }
93 a.Used = true
94 m.authCodes[code] = a
95 return nil
96 }
98 func authCodeGrantValidate(w http.ResponseWriter, r *http.Request, context Context) (scopes []string, profileID uuid.ID, valid bool) {
99 enc := json.NewEncoder(w)
100 code := r.PostFormValue("code")
101 if code == "" {
102 w.WriteHeader(http.StatusBadRequest)
103 renderJSONError(enc, "invalid_request")
104 return
105 }
106 clientID, _, ok := getClientAuth(w, r, true)
107 if !ok {
108 return
109 }
110 authCode, err := context.GetAuthorizationCode(code)
111 if err != nil {
112 if err == ErrAuthorizationCodeNotFound {
113 w.WriteHeader(http.StatusBadRequest)
114 renderJSONError(enc, "invalid_grant")
115 return
116 }
117 w.WriteHeader(http.StatusInternalServerError)
118 renderJSONError(enc, "server_error")
119 return
120 }
121 redirectURI := r.PostFormValue("redirect_uri")
122 if authCode.RedirectURI != redirectURI {
123 w.WriteHeader(http.StatusBadRequest)
124 renderJSONError(enc, "invalid_grant")
125 return
126 }
127 if !authCode.ClientID.Equal(clientID) {
128 w.WriteHeader(http.StatusBadRequest)
129 renderJSONError(enc, "invalid_grant")
130 return
131 }
132 return authCode.Scopes, authCode.ProfileID, true
133 }
135 func authCodeGrantInvalidate(r *http.Request, context Context) error {
136 code := r.PostFormValue("code")
137 if code == "" {
138 return ErrAuthorizationCodeNotFound
139 }
140 return context.UseAuthorizationCode(code)
141 }
143 func authCodeGrantAuditString(r *http.Request) string {
144 return "authcode:" + r.PostFormValue("code")
145 }