diff options
author | KN4CK3R <admin@oldschoolhack.me> | 2021-08-21 04:16:45 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-20 22:16:45 -0400 |
commit | 0bd58d61e547f482dd3c38a30fccb4c58caf2a67 (patch) | |
tree | fbc87f7c8d550db4d54fe930f98d92db0e4b901d /routers | |
parent | e9747de95242807a6319e146216575676de66f47 (diff) | |
download | gitea-0bd58d61e547f482dd3c38a30fccb4c58caf2a67.tar.gz gitea-0bd58d61e547f482dd3c38a30fccb4c58caf2a67.zip |
Added introspection endpoint. (#16752)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Diffstat (limited to 'routers')
-rw-r--r-- | routers/web/user/oauth.go | 98 | ||||
-rw-r--r-- | routers/web/web.go | 1 |
2 files changed, 44 insertions, 55 deletions
diff --git a/routers/web/user/oauth.go b/routers/web/user/oauth.go index 67e4ea0622..771bd90b15 100644 --- a/routers/web/user/oauth.go +++ b/routers/web/user/oauth.go @@ -96,24 +96,6 @@ func (err AccessTokenError) Error() string { return fmt.Sprintf("%s: %s", err.ErrorCode, err.ErrorDescription) } -// BearerTokenErrorCode represents an error code specified in RFC 6750 -type BearerTokenErrorCode string - -const ( - // BearerTokenErrorCodeInvalidRequest represents an error code specified in RFC 6750 - BearerTokenErrorCodeInvalidRequest BearerTokenErrorCode = "invalid_request" - // BearerTokenErrorCodeInvalidToken represents an error code specified in RFC 6750 - BearerTokenErrorCodeInvalidToken BearerTokenErrorCode = "invalid_token" - // BearerTokenErrorCodeInsufficientScope represents an error code specified in RFC 6750 - BearerTokenErrorCodeInsufficientScope BearerTokenErrorCode = "insufficient_scope" -) - -// BearerTokenError represents an error response specified in RFC 6750 -type BearerTokenError struct { - ErrorCode BearerTokenErrorCode `json:"error" form:"error"` - ErrorDescription string `json:"error_description"` -} - // TokenType specifies the kind of token type TokenType string @@ -253,35 +235,56 @@ type userInfoResponse struct { // InfoOAuth manages request for userinfo endpoint func InfoOAuth(ctx *context.Context) { - header := ctx.Req.Header.Get("Authorization") - auths := strings.Fields(header) - if len(auths) != 2 || auths[0] != "Bearer" { - ctx.HandleText(http.StatusUnauthorized, "no valid auth token authorization") - return - } - uid := auth.CheckOAuthAccessToken(auths[1]) - if uid == 0 { - handleBearerTokenError(ctx, BearerTokenError{ - ErrorCode: BearerTokenErrorCodeInvalidToken, - ErrorDescription: "Access token not assigned to any user", - }) - return - } - authUser, err := models.GetUserByID(uid) - if err != nil { - ctx.ServerError("GetUserByID", err) + if ctx.User == nil || ctx.Data["AuthedMethod"] != (&auth.OAuth2{}).Name() { + ctx.Resp.Header().Set("WWW-Authenticate", `Bearer realm=""`) + ctx.HandleText(http.StatusUnauthorized, "no valid authorization") return } response := &userInfoResponse{ - Sub: fmt.Sprint(authUser.ID), - Name: authUser.FullName, - Username: authUser.Name, - Email: authUser.Email, - Picture: authUser.AvatarLink(), + Sub: fmt.Sprint(ctx.User.ID), + Name: ctx.User.FullName, + Username: ctx.User.Name, + Email: ctx.User.Email, + Picture: ctx.User.AvatarLink(), } ctx.JSON(http.StatusOK, response) } +// IntrospectOAuth introspects an oauth token +func IntrospectOAuth(ctx *context.Context) { + if ctx.User == nil { + ctx.Resp.Header().Set("WWW-Authenticate", `Bearer realm=""`) + ctx.HandleText(http.StatusUnauthorized, "no valid authorization") + return + } + + var response struct { + Active bool `json:"active"` + Scope string `json:"scope,omitempty"` + jwt.StandardClaims + } + + form := web.GetForm(ctx).(*forms.IntrospectTokenForm) + token, err := oauth2.ParseToken(form.Token) + if err == nil { + if token.Valid() == nil { + grant, err := models.GetOAuth2GrantByID(token.GrantID) + if err == nil && grant != nil { + app, err := models.GetOAuth2ApplicationByID(grant.ApplicationID) + if err == nil && app != nil { + response.Active = true + response.Scope = grant.Scope + response.Issuer = setting.AppURL + response.Audience = app.ClientID + response.Subject = fmt.Sprint(grant.UserID) + } + } + } + } + + ctx.JSON(http.StatusOK, response) +} + // AuthorizeOAuth manages authorize requests func AuthorizeOAuth(ctx *context.Context) { form := web.GetForm(ctx).(*forms.AuthorizationForm) @@ -697,18 +700,3 @@ func handleAuthorizeError(ctx *context.Context, authErr AuthorizeError, redirect redirect.RawQuery = q.Encode() ctx.Redirect(redirect.String(), 302) } - -func handleBearerTokenError(ctx *context.Context, beErr BearerTokenError) { - ctx.Resp.Header().Set("WWW-Authenticate", fmt.Sprintf("Bearer realm=\"\", error=\"%s\", error_description=\"%s\"", beErr.ErrorCode, beErr.ErrorDescription)) - switch beErr.ErrorCode { - case BearerTokenErrorCodeInvalidRequest: - ctx.JSON(http.StatusBadRequest, beErr) - case BearerTokenErrorCodeInvalidToken: - ctx.JSON(http.StatusUnauthorized, beErr) - case BearerTokenErrorCodeInsufficientScope: - ctx.JSON(http.StatusForbidden, beErr) - default: - log.Error("Invalid BearerTokenErrorCode: %v", beErr.ErrorCode) - ctx.ServerError("Unhandled BearerTokenError", fmt.Errorf("BearerTokenError: error=\"%v\", error_description=\"%v\"", beErr.ErrorCode, beErr.ErrorDescription)) - } -} diff --git a/routers/web/web.go b/routers/web/web.go index a47fd518ac..98395578f6 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -311,6 +311,7 @@ func RegisterRoutes(m *web.Route) { m.Get("/login/oauth/userinfo", ignSignInAndCsrf, user.InfoOAuth) m.Post("/login/oauth/access_token", CorsHandler(), bindIgnErr(forms.AccessTokenForm{}), ignSignInAndCsrf, user.AccessTokenOAuth) m.Get("/login/oauth/keys", ignSignInAndCsrf, user.OIDCKeys) + m.Post("/login/oauth/introspect", CorsHandler(), bindIgnErr(forms.IntrospectTokenForm{}), ignSignInAndCsrf, user.IntrospectOAuth) m.Group("/user/settings", func() { m.Get("", userSetting.Profile) |