auth

Paddy 2015-06-29 Parent:cf1aef6eb81f Child:b7e685839a1b

175:aa14e29b666f Go to Latest

auth/authcode.go

Create Docker image for authd. Create a Dockerfile for authd, which will wrap the compiled Go binary up into a tiny little Docker image. Create an authd/build-docker.sh script that will build the statically-linked binary in a Docker container, so the authd Docker image can use it. We had to include ca-certificates.crt in the Dockerfile, as well, so we could communicate over SSL with things. A wrapper.sh file is included that will pull the JWT_SECRET environment variable out of a kubernetes secrets file, which is a handy wrapper to have. Finally, we added the authd/docker-authd binary to the .hgignore.

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 Scopes
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 deleteAuthorizationCodesByProfileID(profileID uuid.ID) error
52 deleteAuthorizationCodesByClientID(clientID uuid.ID) error
53 useAuthorizationCode(code string) error
54 }
56 func (m *memstore) getAuthorizationCode(code string) (AuthorizationCode, error) {
57 m.authCodeLock.RLock()
58 defer m.authCodeLock.RUnlock()
59 authCode, ok := m.authCodes[code]
60 if !ok {
61 return AuthorizationCode{}, ErrAuthorizationCodeNotFound
62 }
63 return authCode, nil
64 }
66 func (m *memstore) saveAuthorizationCode(authCode AuthorizationCode) error {
67 m.authCodeLock.Lock()
68 defer m.authCodeLock.Unlock()
69 _, ok := m.authCodes[authCode.Code]
70 if ok {
71 return ErrAuthorizationCodeAlreadyExists
72 }
73 m.authCodes[authCode.Code] = authCode
74 return nil
75 }
77 func (m *memstore) deleteAuthorizationCode(code string) error {
78 m.authCodeLock.Lock()
79 defer m.authCodeLock.Unlock()
80 _, ok := m.authCodes[code]
81 if !ok {
82 return ErrAuthorizationCodeNotFound
83 }
84 delete(m.authCodes, code)
85 return nil
86 }
88 func (m *memstore) deleteAuthorizationCodesByProfileID(profileID uuid.ID) error {
89 m.authCodeLock.Lock()
90 defer m.authCodeLock.Unlock()
91 var codes []string
92 for _, code := range m.authCodes {
93 if code.ProfileID.Equal(profileID) {
94 codes = append(codes, code.Code)
95 }
96 }
97 if len(codes) < 1 {
98 return ErrProfileNotFound
99 }
100 for _, code := range codes {
101 delete(m.authCodes, code)
102 }
103 return nil
104 }
106 func (m *memstore) deleteAuthorizationCodesByClientID(clientID uuid.ID) error {
107 m.authCodeLock.Lock()
108 defer m.authCodeLock.Unlock()
109 var codes []string
110 for _, code := range m.authCodes {
111 if code.ClientID.Equal(clientID) {
112 codes = append(codes, code.Code)
113 }
114 }
115 if len(codes) < 1 {
116 return ErrClientNotFound
117 }
118 for _, code := range codes {
119 delete(m.authCodes, code)
120 }
121 return nil
122 }
124 func (m *memstore) useAuthorizationCode(code string) error {
125 m.authCodeLock.Lock()
126 defer m.authCodeLock.Unlock()
127 a, ok := m.authCodes[code]
128 if !ok {
129 return ErrAuthorizationCodeNotFound
130 }
131 a.Used = true
132 m.authCodes[code] = a
133 return nil
134 }
136 func authCodeGrantValidate(w http.ResponseWriter, r *http.Request, context Context) (scopes Scopes, profileID uuid.ID, valid bool) {
137 enc := json.NewEncoder(w)
138 code := r.PostFormValue("code")
139 if code == "" {
140 w.WriteHeader(http.StatusBadRequest)
141 renderJSONError(enc, "invalid_request")
142 return
143 }
144 clientID, _, ok := getClientAuth(w, r, true)
145 if !ok {
146 return
147 }
148 authCode, err := context.GetAuthorizationCode(code)
149 if err != nil {
150 if err == ErrAuthorizationCodeNotFound {
151 w.WriteHeader(http.StatusBadRequest)
152 renderJSONError(enc, "invalid_grant")
153 return
154 }
155 w.WriteHeader(http.StatusInternalServerError)
156 renderJSONError(enc, "server_error")
157 return
158 }
159 redirectURI := r.PostFormValue("redirect_uri")
160 if authCode.RedirectURI != redirectURI {
161 w.WriteHeader(http.StatusBadRequest)
162 renderJSONError(enc, "invalid_grant")
163 return
164 }
165 if !authCode.ClientID.Equal(clientID) {
166 w.WriteHeader(http.StatusBadRequest)
167 renderJSONError(enc, "invalid_grant")
168 return
169 }
170 return authCode.Scopes, authCode.ProfileID, true
171 }
173 func authCodeGrantInvalidate(r *http.Request, context Context) error {
174 code := r.PostFormValue("code")
175 if code == "" {
176 return ErrAuthorizationCodeNotFound
177 }
178 return context.UseAuthorizationCode(code)
179 }
181 func authCodeGrantAuditString(r *http.Request) string {
182 return "authcode:" + r.PostFormValue("code")
183 }