auth
auth/authcode.go
Remove old BUG. We implemented revoking tokens, so let's remove the BUG designation.
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 // ErrNoAuthorizationCodeStore is returned when a Context tries to act on a authorizationCodeStore without setting one first.
22 ErrNoAuthorizationCodeStore = errors.New("no authorizationCodeStore was specified for the Context")
23 // ErrAuthorizationCodeNotFound is returned when an AuthorizationCode is requested but not found in the authorizationCodeStore.
24 ErrAuthorizationCodeNotFound = errors.New("authorization code not found in authorizationCodeStore")
25 // ErrAuthorizationCodeAlreadyExists is returned when an AuthorizationCode is added to a authorizationCodeStore, but another AuthorizationCode with the
26 // same Code already exists in the authorizationCodeStore.
27 ErrAuthorizationCodeAlreadyExists = errors.New("authorization code already exists in authorizationCodeStore")
28 )
30 // AuthorizationCode 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 AuthorizationCode 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 authorizationCodeStore interface {
44 getAuthorizationCode(code string) (AuthorizationCode, error)
45 saveAuthorizationCode(authCode AuthorizationCode) error
46 deleteAuthorizationCode(code string) error
47 }
49 func (m *memstore) getAuthorizationCode(code string) (AuthorizationCode, error) {
50 m.authCodeLock.RLock()
51 defer m.authCodeLock.RUnlock()
52 authCode, ok := m.authCodes[code]
53 if !ok {
54 return AuthorizationCode{}, ErrAuthorizationCodeNotFound
55 }
56 return authCode, nil
57 }
59 func (m *memstore) saveAuthorizationCode(authCode AuthorizationCode) error {
60 m.authCodeLock.Lock()
61 defer m.authCodeLock.Unlock()
62 _, ok := m.authCodes[authCode.Code]
63 if ok {
64 return ErrAuthorizationCodeAlreadyExists
65 }
66 m.authCodes[authCode.Code] = authCode
67 return nil
68 }
70 func (m *memstore) deleteAuthorizationCode(code string) error {
71 m.authCodeLock.Lock()
72 defer m.authCodeLock.Unlock()
73 _, ok := m.authCodes[code]
74 if !ok {
75 return ErrAuthorizationCodeNotFound
76 }
77 delete(m.authCodes, 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 authCode, err := context.GetAuthorizationCode(code)
94 if err != nil {
95 if err == ErrAuthorizationCodeNotFound {
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 authCode.RedirectURI != redirectURI {
106 w.WriteHeader(http.StatusBadRequest)
107 renderJSONError(enc, "invalid_grant")
108 return
109 }
110 if !authCode.ClientID.Equal(clientID) {
111 w.WriteHeader(http.StatusBadRequest)
112 renderJSONError(enc, "invalid_grant")
113 return
114 }
115 return authCode.Scope, authCode.ProfileID, true
116 }
118 func authCodeGrantInvalidate(r *http.Request, context Context) error {
119 // TODO(paddy): implement marking the authcode as used.
120 return nil
121 }