mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Show OAuth2 errors to end users (#25261)
Partially fix #23936   
This commit is contained in:
		| @@ -2901,7 +2901,7 @@ auths.sspi_default_language = Default user language | |||||||
| auths.sspi_default_language_helper = Default language for users automatically created by SSPI auth method. Leave empty if you prefer language to be automatically detected. | auths.sspi_default_language_helper = Default language for users automatically created by SSPI auth method. Leave empty if you prefer language to be automatically detected. | ||||||
| auths.tips = Tips | auths.tips = Tips | ||||||
| auths.tips.oauth2.general = OAuth2 Authentication | auths.tips.oauth2.general = OAuth2 Authentication | ||||||
| auths.tips.oauth2.general.tip = When registering a new OAuth2 authentication, the callback/redirect URL should be: <host>/user/oauth2/<Authentication Name>/callback | auths.tips.oauth2.general.tip = When registering a new OAuth2 authentication, the callback/redirect URL should be: | ||||||
| auths.tip.oauth2_provider = OAuth2 Provider | auths.tip.oauth2_provider = OAuth2 Provider | ||||||
| auths.tip.bitbucket = Register a new OAuth consumer on https://bitbucket.org/account/user/<your username>/oauth-consumers/new and add the permission 'Account' - 'Read' | auths.tip.bitbucket = Register a new OAuth consumer on https://bitbucket.org/account/user/<your username>/oauth-consumers/new and add the permission 'Account' - 'Read' | ||||||
| auths.tip.nextcloud = Register a new OAuth consumer on your instance using the following menu "Settings -> Security -> OAuth 2.0 client" | auths.tip.nextcloud = Register a new OAuth consumer on your instance using the following menu "Settings -> Security -> OAuth 2.0 client" | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
| package auth | package auth | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	stdContext "context" | 	go_context "context" | ||||||
| 	"encoding/base64" | 	"encoding/base64" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| @@ -12,6 +12,7 @@ import ( | |||||||
| 	"io" | 	"io" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/url" | 	"net/url" | ||||||
|  | 	"sort" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models/auth" | 	"code.gitea.io/gitea/models/auth" | ||||||
| @@ -39,6 +40,7 @@ import ( | |||||||
| 	"github.com/golang-jwt/jwt/v4" | 	"github.com/golang-jwt/jwt/v4" | ||||||
| 	"github.com/markbates/goth" | 	"github.com/markbates/goth" | ||||||
| 	"github.com/markbates/goth/gothic" | 	"github.com/markbates/goth/gothic" | ||||||
|  | 	go_oauth2 "golang.org/x/oauth2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -143,7 +145,7 @@ type AccessTokenResponse struct { | |||||||
| 	IDToken      string    `json:"id_token,omitempty"` | 	IDToken      string    `json:"id_token,omitempty"` | ||||||
| } | } | ||||||
|  |  | ||||||
| func newAccessTokenResponse(ctx stdContext.Context, grant *auth.OAuth2Grant, serverKey, clientKey oauth2.JWTSigningKey) (*AccessTokenResponse, *AccessTokenError) { | func newAccessTokenResponse(ctx go_context.Context, grant *auth.OAuth2Grant, serverKey, clientKey oauth2.JWTSigningKey) (*AccessTokenResponse, *AccessTokenError) { | ||||||
| 	if setting.OAuth2.InvalidateRefreshTokens { | 	if setting.OAuth2.InvalidateRefreshTokens { | ||||||
| 		if err := grant.IncreaseCounter(ctx); err != nil { | 		if err := grant.IncreaseCounter(ctx); err != nil { | ||||||
| 			return nil, &AccessTokenError{ | 			return nil, &AccessTokenError{ | ||||||
| @@ -886,6 +888,17 @@ func SignInOAuth(ctx *context.Context) { | |||||||
| func SignInOAuthCallback(ctx *context.Context) { | func SignInOAuthCallback(ctx *context.Context) { | ||||||
| 	provider := ctx.Params(":provider") | 	provider := ctx.Params(":provider") | ||||||
|  |  | ||||||
|  | 	if ctx.Req.FormValue("error") != "" { | ||||||
|  | 		var errorKeyValues []string | ||||||
|  | 		for k, vv := range ctx.Req.Form { | ||||||
|  | 			for _, v := range vv { | ||||||
|  | 				errorKeyValues = append(errorKeyValues, fmt.Sprintf("%s = %s", html.EscapeString(k), html.EscapeString(v))) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		sort.Strings(errorKeyValues) | ||||||
|  | 		ctx.Flash.Error(strings.Join(errorKeyValues, "<br>"), true) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// first look if the provider is still active | 	// first look if the provider is still active | ||||||
| 	authSource, err := auth.GetActiveOAuth2SourceByName(provider) | 	authSource, err := auth.GetActiveOAuth2SourceByName(provider) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -894,7 +907,7 @@ func SignInOAuthCallback(ctx *context.Context) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if authSource == nil { | 	if authSource == nil { | ||||||
| 		ctx.ServerError("SignIn", errors.New("No valid provider found, check configured callback url in provider")) | 		ctx.ServerError("SignIn", errors.New("no valid provider found, check configured callback url in provider")) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -920,6 +933,9 @@ func SignInOAuthCallback(ctx *context.Context) { | |||||||
| 			ctx.Redirect(setting.AppSubURL + "/user/login") | 			ctx.Redirect(setting.AppSubURL + "/user/login") | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  | 		if err, ok := err.(*go_oauth2.RetrieveError); ok { | ||||||
|  | 			ctx.Flash.Error("OAuth2 RetrieveError: "+err.Error(), true) | ||||||
|  | 		} | ||||||
| 		ctx.ServerError("UserSignIn", err) | 		ctx.ServerError("UserSignIn", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -14,8 +14,8 @@ | |||||||
| 					<span>{{.Source.TypeName}}</span> | 					<span>{{.Source.TypeName}}</span> | ||||||
| 				</div> | 				</div> | ||||||
| 				<div class="required inline field {{if .Err_Name}}error{{end}}"> | 				<div class="required inline field {{if .Err_Name}}error{{end}}"> | ||||||
| 					<label for="name">{{.locale.Tr "admin.auths.auth_name"}}</label> | 					<label for="auth_name">{{.locale.Tr "admin.auths.auth_name"}}</label> | ||||||
| 					<input id="name" name="name" value="{{.Source.Name}}" autofocus required> | 					<input id="auth_name" name="name" value="{{.Source.Name}}" autofocus required> | ||||||
| 				</div> | 				</div> | ||||||
|  |  | ||||||
| 				<!-- LDAP and DLDAP --> | 				<!-- LDAP and DLDAP --> | ||||||
| @@ -434,6 +434,17 @@ | |||||||
| 				</div> | 				</div> | ||||||
| 			</form> | 			</form> | ||||||
| 		</div> | 		</div> | ||||||
|  |  | ||||||
|  | 		<h4 class="ui top attached header"> | ||||||
|  | 			{{.locale.Tr "admin.auths.tips"}} | ||||||
|  | 		</h4> | ||||||
|  | 		<div class="ui attached segment"> | ||||||
|  | 			<h5>GMail Settings:</h5> | ||||||
|  | 			<p>Host: smtp.gmail.com, Port: 587, Enable TLS Encryption: true</p> | ||||||
|  |  | ||||||
|  | 			<h5 class="oauth2">{{.locale.Tr "admin.auths.tips.oauth2.general"}}:</h5> | ||||||
|  | 			<p class="oauth2">{{.locale.Tr "admin.auths.tips.oauth2.general.tip"}} <b id="oauth2-callback-url"></b></p> | ||||||
|  | 		</div> | ||||||
| 	</div> | 	</div> | ||||||
|  |  | ||||||
| <div class="ui g-modal-confirm delete modal"> | <div class="ui g-modal-confirm delete modal"> | ||||||
|   | |||||||
| @@ -22,8 +22,8 @@ | |||||||
| 					</div> | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
| 				<div class="required inline field {{if .Err_Name}}error{{end}}"> | 				<div class="required inline field {{if .Err_Name}}error{{end}}"> | ||||||
| 					<label for="name">{{.locale.Tr "admin.auths.auth_name"}}</label> | 					<label for="auth_name">{{.locale.Tr "admin.auths.auth_name"}}</label> | ||||||
| 					<input id="name" name="name" value="{{.name}}" autofocus required> | 					<input id="auth_name" name="name" value="{{.name}}" autofocus required> | ||||||
| 				</div> | 				</div> | ||||||
|  |  | ||||||
| 				<!-- LDAP and DLDAP --> | 				<!-- LDAP and DLDAP --> | ||||||
| @@ -85,8 +85,8 @@ | |||||||
| 			<h5>GMail Settings:</h5> | 			<h5>GMail Settings:</h5> | ||||||
| 			<p>Host: smtp.gmail.com, Port: 587, Enable TLS Encryption: true</p> | 			<p>Host: smtp.gmail.com, Port: 587, Enable TLS Encryption: true</p> | ||||||
|  |  | ||||||
| 			<h5>{{.locale.Tr "admin.auths.tips.oauth2.general"}}:</h5> | 			<h5 class="oauth2">{{.locale.Tr "admin.auths.tips.oauth2.general"}}:</h5> | ||||||
| 			<p>{{.locale.Tr "admin.auths.tips.oauth2.general.tip"}}</p> | 			<p class="oauth2">{{.locale.Tr "admin.auths.tips.oauth2.general.tip"}} <b id="oauth2-callback-url"></b></p> | ||||||
|  |  | ||||||
| 			<h5 class="ui top attached header">{{.locale.Tr "admin.auths.tip.oauth2_provider"}}</h5> | 			<h5 class="ui top attached header">{{.locale.Tr "admin.auths.tip.oauth2_provider"}}</h5> | ||||||
| 			<div class="ui attached segment"> | 			<div class="ui attached segment"> | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| {{/* This page should only depend the minimal template functions/variables, to avoid triggering new panics. | {{/* This page should only depend the minimal template functions/variables, to avoid triggering new panics. | ||||||
| * base template functions: AppName, AssetUrlPrefix, AssetVersion, AppSubUrl, DefaultTheme, Str2html | * base template functions: AppName, AssetUrlPrefix, AssetVersion, AppSubUrl, DefaultTheme, Str2html | ||||||
| * locale | * locale | ||||||
|  | * Flash | ||||||
| * ErrorMsg | * ErrorMsg | ||||||
| * SignedUser (optional) | * SignedUser (optional) | ||||||
| */}} | */}} | ||||||
| @@ -28,6 +29,10 @@ | |||||||
| 			</div> | 			</div> | ||||||
| 		</nav> | 		</nav> | ||||||
| 		<div role="main" class="page-content status-page-500"> | 		<div role="main" class="page-content status-page-500"> | ||||||
|  | 			<div class="ui container" > | ||||||
|  | 				<style> .ui.message.flash-message { text-align: left; } </style> | ||||||
|  | 				{{template "base/alert" .}} | ||||||
|  | 			</div> | ||||||
| 			<p class="gt-mt-5 center"><img src="{{AssetUrlPrefix}}/img/500.png" alt="Internal Server Error"></p> | 			<p class="gt-mt-5 center"><img src="{{AssetUrlPrefix}}/img/500.png" alt="Internal Server Error"></p> | ||||||
| 			<div class="ui divider"></div> | 			<div class="ui divider"></div> | ||||||
| 			<div class="ui container gt-my-5"> | 			<div class="ui container gt-my-5"> | ||||||
|   | |||||||
| @@ -171,6 +171,12 @@ export function initAdminCommon() { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   if ($('.admin.authentication').length > 0) { | ||||||
|  |     $('#auth_name').on('input', function () { | ||||||
|  |       $('#oauth2-callback-url').text(`${window.location.origin}/user/oauth2/${encodeURIComponent($(this).val())}/callback`); | ||||||
|  |     }).trigger('input'); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   // Notice |   // Notice | ||||||
|   if ($('.admin.notice')) { |   if ($('.admin.notice')) { | ||||||
|     const $detailModal = $('#detail-modal'); |     const $detailModal = $('#detail-modal'); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user