auth

Paddy 2015-12-14 Parent:b7e685839a1b

182:cd5f07f9811b Go to Latest

auth/authcode.go

Update nsq import path. go-nsq has moved to nsqio/go-nsq, so we need to update the import path appropriately.

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