summaryrefslogtreecommitdiffstats
path: root/routers
diff options
context:
space:
mode:
authorKN4CK3R <admin@oldschoolhack.me>2021-08-21 04:16:45 +0200
committerGitHub <noreply@github.com>2021-08-20 22:16:45 -0400
commit0bd58d61e547f482dd3c38a30fccb4c58caf2a67 (patch)
treefbc87f7c8d550db4d54fe930f98d92db0e4b901d /routers
parente9747de95242807a6319e146216575676de66f47 (diff)
downloadgitea-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.go98
-rw-r--r--routers/web/web.go1
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)