1 /* 2 * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io> 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * @author Aeneas Rekkas <aeneas+oss@aeneas.io> 17 * @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io> 18 * @license Apache-2.0 19 * 20 */ 21 22 package fosite 23 24 import ( 25 "context" 26 "net/http" 27 "net/url" 28 "time" 29 30 "golang.org/x/text/language" 31 ) 32 33 type TokenUse = TokenType 34 35 type TokenType string 36 37 const ( 38 AccessToken TokenType = "access_token" 39 RefreshToken TokenType = "refresh_token" 40 AuthorizeCode TokenType = "authorize_code" 41 IDToken TokenType = "id_token" 42 43 BearerAccessToken string = "bearer" 44 ) 45 46 // OAuth2Provider is an interface that enables you to write OAuth2 handlers with only a few lines of code. 47 // Check fosite.Fosite for an implementation of this interface. 48 type OAuth2Provider interface { 49 // NewAuthorizeRequest returns an AuthorizeRequest. 50 // 51 // The following specs must be considered in any implementation of this method: 52 // * https://tools.ietf.org/html/rfc6749#section-3.1 53 // Extension response types MAY contain a space-delimited (%x20) list of 54 // values, where the order of values does not matter (e.g., response 55 // type "a b" is the same as "b a"). The meaning of such composite 56 // response types is defined by their respective specifications. 57 // * https://tools.ietf.org/html/rfc6749#section-3.1.2 58 // The redirection endpoint URI MUST be an absolute URI as defined by 59 // [RFC3986] Section 4.3. The endpoint URI MAY include an 60 // "application/x-www-form-urlencoded" formatted (per Appendix B) query 61 // component ([RFC3986] Section 3.4), which MUST be retained when adding 62 // additional query parameters. The endpoint URI MUST NOT include a 63 // fragment component. 64 // * https://tools.ietf.org/html/rfc6749#section-3.1.2.2 (everything MUST be implemented) 65 NewAuthorizeRequest(ctx context.Context, req *http.Request) (AuthorizeRequester, error) 66 67 // NewAuthorizeResponse iterates through all response type handlers and returns their result or 68 // ErrUnsupportedResponseType if none of the handler's were able to handle it. 69 // 70 // The following specs must be considered in any implementation of this method: 71 // * https://tools.ietf.org/html/rfc6749#section-3.1.1 72 // Extension response types MAY contain a space-delimited (%x20) list of 73 // values, where the order of values does not matter (e.g., response 74 // type "a b" is the same as "b a"). The meaning of such composite 75 // response types is defined by their respective specifications. 76 // If an authorization request is missing the "response_type" parameter, 77 // or if the response type is not understood, the authorization server 78 // MUST return an error response as described in Section 4.1.2.1. 79 NewAuthorizeResponse(ctx context.Context, requester AuthorizeRequester, session Session) (AuthorizeResponder, error) 80 81 // WriteAuthorizeError returns the error codes to the redirection endpoint or shows the error to the user, if no valid 82 // redirect uri was given. Implements rfc6749#section-4.1.2.1 83 // 84 // The following specs must be considered in any implementation of this method: 85 // * https://tools.ietf.org/html/rfc6749#section-3.1.2 86 // The redirection endpoint URI MUST be an absolute URI as defined by 87 // [RFC3986] Section 4.3. The endpoint URI MAY include an 88 // "application/x-www-form-urlencoded" formatted (per Appendix B) query 89 // component ([RFC3986] Section 3.4), which MUST be retained when adding 90 // additional query parameters. The endpoint URI MUST NOT include a 91 // fragment component. 92 // * https://tools.ietf.org/html/rfc6749#section-4.1.2.1 (everything) 93 // * https://tools.ietf.org/html/rfc6749#section-3.1.2.2 (everything MUST be implemented) 94 WriteAuthorizeError(rw http.ResponseWriter, requester AuthorizeRequester, err error) 95 96 // WriteAuthorizeResponse persists the AuthorizeSession in the store and redirects the user agent to the provided 97 // redirect url or returns an error if storage failed. 98 // 99 // The following specs must be considered in any implementation of this method: 100 // * https://tools.ietf.org/html/rfc6749#rfc6749#section-4.1.2.1 101 // After completing its interaction with the resource owner, the 102 // authorization server directs the resource owner's user-agent back to 103 // the client. The authorization server redirects the user-agent to the 104 // client's redirection endpoint previously established with the 105 // authorization server during the client registration process or when 106 // making the authorization request. 107 // * https://tools.ietf.org/html/rfc6749#section-3.1.2.2 (everything MUST be implemented) 108 WriteAuthorizeResponse(rw http.ResponseWriter, requester AuthorizeRequester, responder AuthorizeResponder) 109 110 // NewAccessRequest creates a new access request object and validates 111 // various parameters. 112 // 113 // The following specs must be considered in any implementation of this method: 114 // * https://tools.ietf.org/html/rfc6749#section-3.2 (everything) 115 // * https://tools.ietf.org/html/rfc6749#section-3.2.1 (everything) 116 // 117 // Furthermore the registered handlers should implement their specs accordingly. 118 NewAccessRequest(ctx context.Context, req *http.Request, session Session) (AccessRequester, error) 119 120 // NewAccessResponse creates a new access response and validates that access_token and token_type are set. 121 // 122 // The following specs must be considered in any implementation of this method: 123 // https://tools.ietf.org/html/rfc6749#section-5.1 124 NewAccessResponse(ctx context.Context, requester AccessRequester) (AccessResponder, error) 125 126 // WriteAccessError writes an access request error response. 127 // 128 // The following specs must be considered in any implementation of this method: 129 // * https://tools.ietf.org/html/rfc6749#section-5.2 (everything) 130 WriteAccessError(rw http.ResponseWriter, requester AccessRequester, err error) 131 132 // WriteAccessResponse writes the access response. 133 // 134 // The following specs must be considered in any implementation of this method: 135 // https://tools.ietf.org/html/rfc6749#section-5.1 136 WriteAccessResponse(rw http.ResponseWriter, requester AccessRequester, responder AccessResponder) 137 138 // NewRevocationRequest handles incoming token revocation requests and validates various parameters. 139 // 140 // The following specs must be considered in any implementation of this method: 141 // https://tools.ietf.org/html/rfc7009#section-2.1 142 NewRevocationRequest(ctx context.Context, r *http.Request) error 143 144 // WriteRevocationResponse writes the revoke response. 145 // 146 // The following specs must be considered in any implementation of this method: 147 // https://tools.ietf.org/html/rfc7009#section-2.2 148 WriteRevocationResponse(rw http.ResponseWriter, err error) 149 150 // IntrospectToken returns token metadata, if the token is valid. Tokens generated by the authorization endpoint, 151 // such as the authorization code, can not be introspected. 152 IntrospectToken(ctx context.Context, token string, tokenUse TokenUse, session Session, scope ...string) (TokenUse, AccessRequester, error) 153 154 // NewIntrospectionRequest initiates token introspection as defined in 155 // https://tools.ietf.org/search/rfc7662#section-2.1 156 NewIntrospectionRequest(ctx context.Context, r *http.Request, session Session) (IntrospectionResponder, error) 157 158 // WriteIntrospectionError responds with an error if token introspection failed as defined in 159 // https://tools.ietf.org/search/rfc7662#section-2.3 160 WriteIntrospectionError(rw http.ResponseWriter, err error) 161 162 // WriteIntrospectionResponse responds with token metadata discovered by token introspection as defined in 163 // https://tools.ietf.org/search/rfc7662#section-2.2 164 WriteIntrospectionResponse(rw http.ResponseWriter, r IntrospectionResponder) 165 } 166 167 // IntrospectionResponder is the response object that will be returned when token introspection was successful, 168 // for example when the client is allowed to perform token introspection. Refer to 169 // https://tools.ietf.org/search/rfc7662#section-2.2 for more details. 170 type IntrospectionResponder interface { 171 // IsActive returns true if the introspected token is active and false otherwise. 172 IsActive() bool 173 174 // AccessRequester returns nil when IsActive() is false and the original access request object otherwise. 175 GetAccessRequester() AccessRequester 176 177 // GetTokenUse optionally returns the type of the token that was introspected. This could be "access_token", "refresh_token", 178 // or if the type can not be determined an empty string. 179 GetTokenUse() TokenUse 180 181 //GetAccessTokenType optionally returns the type of the access token that was introspected. This could be "bearer", "mac", 182 // or empty string if the type of the token is refresh token. 183 GetAccessTokenType() string 184 } 185 186 // Requester is an abstract interface for handling requests in Fosite. 187 type Requester interface { 188 // SetID sets the unique identifier. 189 SetID(id string) 190 191 // GetID returns a unique identifier. 192 GetID() string 193 194 // GetRequestedAt returns the time the request was created. 195 GetRequestedAt() (requestedAt time.Time) 196 197 // GetClient returns the request's client. 198 GetClient() (client Client) 199 200 // GetRequestedScopes returns the request's scopes. 201 GetRequestedScopes() (scopes Arguments) 202 203 // GetRequestedAudience returns the requested audiences for this request. 204 GetRequestedAudience() (audience Arguments) 205 206 // SetRequestedScopes sets the request's scopes. 207 SetRequestedScopes(scopes Arguments) 208 209 // SetRequestedAudience sets the requested audience. 210 SetRequestedAudience(audience Arguments) 211 212 // AppendRequestedScope appends a scope to the request. 213 AppendRequestedScope(scope string) 214 215 // GetGrantScopes returns all granted scopes. 216 GetGrantedScopes() (grantedScopes Arguments) 217 218 // GetGrantedAudience returns all granted audiences. 219 GetGrantedAudience() (grantedAudience Arguments) 220 221 // GrantScope marks a request's scope as granted. 222 GrantScope(scope string) 223 224 // GrantAudience marks a request's audience as granted. 225 GrantAudience(audience string) 226 227 // GetSession returns a pointer to the request's session or nil if none is set. 228 GetSession() (session Session) 229 230 // SetSession sets the request's session pointer. 231 SetSession(session Session) 232 233 // GetRequestForm returns the request's form input. 234 GetRequestForm() url.Values 235 236 // Merge merges the argument into the method receiver. 237 Merge(requester Requester) 238 239 // Sanitize returns a sanitized clone of the request which can be used for storage. 240 Sanitize(allowedParameters []string) Requester 241 } 242 243 // AccessRequester is a token endpoint's request context. 244 type AccessRequester interface { 245 // GetGrantType returns the requests grant type. 246 GetGrantTypes() (grantTypes Arguments) 247 248 Requester 249 } 250 251 // AuthorizeRequester is an authorize endpoint's request context. 252 type AuthorizeRequester interface { 253 // GetResponseTypes returns the requested response types 254 GetResponseTypes() (responseTypes Arguments) 255 256 // SetResponseTypeHandled marks a response_type (e.g. token or code) as handled indicating that the response type 257 // is supported. 258 SetResponseTypeHandled(responseType string) 259 260 // DidHandleAllResponseTypes returns if all requested response types have been handled correctly 261 DidHandleAllResponseTypes() (didHandle bool) 262 263 // GetRedirectURI returns the requested redirect URI 264 GetRedirectURI() (redirectURL *url.URL) 265 266 // IsRedirectURIValid returns false if the redirect is not rfc-conform (i.e. missing client, not on white list, 267 // or malformed) 268 IsRedirectURIValid() (isValid bool) 269 270 // GetState returns the request's state. 271 GetState() (state string) 272 273 // GetResponseMode returns response_mode of the authorization request 274 GetResponseMode() ResponseModeType 275 276 // SetDefaultResponseMode sets default response mode for a response type in a flow 277 SetDefaultResponseMode(responseMode ResponseModeType) 278 279 // GetDefaultResponseMode gets default response mode for a response type in a flow 280 GetDefaultResponseMode() ResponseModeType 281 282 Requester 283 } 284 285 // AccessResponder is a token endpoint's response. 286 type AccessResponder interface { 287 // SetExtra sets a key value pair for the access response. 288 SetExtra(key string, value interface{}) 289 290 // GetExtra returns a key's value. 291 GetExtra(key string) interface{} 292 293 SetExpiresIn(time.Duration) 294 295 SetScopes(scopes Arguments) 296 297 // SetAccessToken sets the responses mandatory access token. 298 SetAccessToken(token string) 299 300 // SetTokenType set's the responses mandatory token type 301 SetTokenType(tokenType string) 302 303 // SetAccessToken returns the responses access token. 304 GetAccessToken() (token string) 305 306 // GetTokenType returns the responses token type. 307 GetTokenType() (token string) 308 309 // ToMap converts the response to a map. 310 ToMap() map[string]interface{} 311 } 312 313 // AuthorizeResponder is an authorization endpoint's response. 314 type AuthorizeResponder interface { 315 // GetCode returns the response's authorize code if set. 316 GetCode() string 317 318 // GetHeader returns the response's header 319 GetHeader() (header http.Header) 320 321 // AddHeader adds an header key value pair to the response 322 AddHeader(key, value string) 323 324 // GetParameters returns the response's parameters 325 GetParameters() (query url.Values) 326 327 // AddParameter adds key value pair to the response 328 AddParameter(key, value string) 329 } 330 331 // G11NContext is the globalization context 332 type G11NContext interface { 333 // GetLang returns the current language in the context 334 GetLang() language.Tag 335 } 336