Add ability to set multiple redirect URIs in OAuth application UI (#25072)
OAuth applications can already have multiple redirect URIs if created/edited over API. This change allows for setting multiple redirect URIs through the UI as a comma-separated list (e. g. `https://example.org/redirect,https://redirect.example.org`) <details> <summary>Screenshots</summary> ![Bildschirmfoto vom 2023-06-04 17-14-40](https://github.com/go-gitea/gitea/assets/47871822/2206dc32-e7e4-4953-9ecb-e098890b3f54) ![Bildschirmfoto vom 2023-06-04 17-14-50](https://github.com/go-gitea/gitea/assets/47871822/cd97c73c-9310-44ee-a83a-b927a1ef94da) </details> Closes #25068
This commit is contained in:
parent
7d192cb674
commit
ca35dec18b
|
@ -51,14 +51,6 @@ func (app *OAuth2Application) TableName() string {
|
||||||
return "oauth2_application"
|
return "oauth2_application"
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrimaryRedirectURI returns the first redirect uri or an empty string if empty
|
|
||||||
func (app *OAuth2Application) PrimaryRedirectURI() string {
|
|
||||||
if len(app.RedirectURIs) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return app.RedirectURIs[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainsRedirectURI checks if redirectURI is allowed for app
|
// ContainsRedirectURI checks if redirectURI is allowed for app
|
||||||
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
|
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
|
||||||
if !app.ConfidentialClient {
|
if !app.ConfidentialClient {
|
||||||
|
|
|
@ -3,7 +3,10 @@
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import "unicode/utf8"
|
import (
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
// in UTF8 "…" is 3 bytes so doesn't really gain us anything...
|
// in UTF8 "…" is 3 bytes so doesn't really gain us anything...
|
||||||
const (
|
const (
|
||||||
|
@ -35,3 +38,17 @@ func SplitStringAtByteN(input string, n int) (left, right string) {
|
||||||
|
|
||||||
return input[:end] + utf8Ellipsis, utf8Ellipsis + input[end:]
|
return input[:end] + utf8Ellipsis, utf8Ellipsis + input[end:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SplitTrimSpace splits the string at given separator and trims leading and trailing space
|
||||||
|
func SplitTrimSpace(input, sep string) []string {
|
||||||
|
// replace CRLF with LF
|
||||||
|
input = strings.ReplaceAll(input, "\r\n", "\n")
|
||||||
|
|
||||||
|
var stringList []string
|
||||||
|
for _, s := range strings.Split(input, sep) {
|
||||||
|
// trim leading and trailing space
|
||||||
|
stringList = append(stringList, strings.TrimSpace(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringList
|
||||||
|
}
|
||||||
|
|
|
@ -826,7 +826,7 @@ create_oauth2_application_success = You've successfully created a new OAuth2 app
|
||||||
update_oauth2_application_success = You've successfully updated the OAuth2 application.
|
update_oauth2_application_success = You've successfully updated the OAuth2 application.
|
||||||
oauth2_application_name = Application Name
|
oauth2_application_name = Application Name
|
||||||
oauth2_confidential_client = Confidential Client. Select for apps that keep the secret confidential, such as web apps. Do not select for native apps including desktop and mobile apps.
|
oauth2_confidential_client = Confidential Client. Select for apps that keep the secret confidential, such as web apps. Do not select for native apps including desktop and mobile apps.
|
||||||
oauth2_redirect_uri = Redirect URI
|
oauth2_redirect_uris = Redirect URIs. Please use a new line for every URI.
|
||||||
save_application = Save
|
save_application = Save
|
||||||
oauth2_client_id = Client ID
|
oauth2_client_id = Client ID
|
||||||
oauth2_client_secret = Client Secret
|
oauth2_client_secret = Client Secret
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/auth"
|
"code.gitea.io/gitea/models/auth"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
)
|
)
|
||||||
|
@ -40,7 +41,7 @@ func (oa *OAuth2CommonHandlers) AddApp(ctx *context.Context) {
|
||||||
// TODO validate redirect URI
|
// TODO validate redirect URI
|
||||||
app, err := auth.CreateOAuth2Application(ctx, auth.CreateOAuth2ApplicationOptions{
|
app, err := auth.CreateOAuth2Application(ctx, auth.CreateOAuth2ApplicationOptions{
|
||||||
Name: form.Name,
|
Name: form.Name,
|
||||||
RedirectURIs: []string{form.RedirectURI},
|
RedirectURIs: util.SplitTrimSpace(form.RedirectURIs, "\n"),
|
||||||
UserID: oa.OwnerID,
|
UserID: oa.OwnerID,
|
||||||
ConfidentialClient: form.ConfidentialClient,
|
ConfidentialClient: form.ConfidentialClient,
|
||||||
})
|
})
|
||||||
|
@ -93,7 +94,7 @@ func (oa *OAuth2CommonHandlers) EditSave(ctx *context.Context) {
|
||||||
if ctx.Data["App"], err = auth.UpdateOAuth2Application(auth.UpdateOAuth2ApplicationOptions{
|
if ctx.Data["App"], err = auth.UpdateOAuth2Application(auth.UpdateOAuth2ApplicationOptions{
|
||||||
ID: ctx.ParamsInt64("id"),
|
ID: ctx.ParamsInt64("id"),
|
||||||
Name: form.Name,
|
Name: form.Name,
|
||||||
RedirectURIs: []string{form.RedirectURI},
|
RedirectURIs: util.SplitTrimSpace(form.RedirectURIs, "\n"),
|
||||||
UserID: oa.OwnerID,
|
UserID: oa.OwnerID,
|
||||||
ConfidentialClient: form.ConfidentialClient,
|
ConfidentialClient: form.ConfidentialClient,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
@ -398,7 +398,7 @@ func (f *NewAccessTokenForm) GetScope() (auth_model.AccessTokenScope, error) {
|
||||||
// EditOAuth2ApplicationForm form for editing oauth2 applications
|
// EditOAuth2ApplicationForm form for editing oauth2 applications
|
||||||
type EditOAuth2ApplicationForm struct {
|
type EditOAuth2ApplicationForm struct {
|
||||||
Name string `binding:"Required;MaxSize(255)" form:"application_name"`
|
Name string `binding:"Required;MaxSize(255)" form:"application_name"`
|
||||||
RedirectURI string `binding:"Required" form:"redirect_uri"`
|
RedirectURIs string `binding:"Required" form:"redirect_uris"`
|
||||||
ConfidentialClient bool `form:"confidential_client"`
|
ConfidentialClient bool `form:"confidential_client"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,8 @@
|
||||||
<input id="application-name" value="{{.App.Name}}" name="application_name" required maxlength="255">
|
<input id="application-name" value="{{.App.Name}}" name="application_name" required maxlength="255">
|
||||||
</div>
|
</div>
|
||||||
<div class="field {{if .Err_RedirectURI}}error{{end}}">
|
<div class="field {{if .Err_RedirectURI}}error{{end}}">
|
||||||
<label for="redirect-uri">{{.locale.Tr "settings.oauth2_redirect_uri"}}</label>
|
<label for="redirect-uris">{{.locale.Tr "settings.oauth2_redirect_uris"}}</label>
|
||||||
<input type="url" name="redirect_uri" value="{{.App.PrimaryRedirectURI}}" id="redirect-uri" required>
|
<textarea name="redirect_uris" id="redirect-uris" required>{{StringUtils.Join .App.RedirectURIs "\n"}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="field ui checkbox {{if .Err_ConfidentialClient}}error{{end}}">
|
<div class="field ui checkbox {{if .Err_ConfidentialClient}}error{{end}}">
|
||||||
<label>{{.locale.Tr "settings.oauth2_confidential_client"}}</label>
|
<label>{{.locale.Tr "settings.oauth2_confidential_client"}}</label>
|
||||||
|
|
|
@ -34,8 +34,8 @@
|
||||||
<input id="application-name" name="application_name" value="{{.application_name}}" required maxlength="255">
|
<input id="application-name" name="application_name" value="{{.application_name}}" required maxlength="255">
|
||||||
</div>
|
</div>
|
||||||
<div class="field {{if .Err_RedirectURI}}error{{end}}">
|
<div class="field {{if .Err_RedirectURI}}error{{end}}">
|
||||||
<label for="redirect-uri">{{.locale.Tr "settings.oauth2_redirect_uri"}}</label>
|
<label for="redirect-uris">{{.locale.Tr "settings.oauth2_redirect_uris"}}</label>
|
||||||
<input type="url" name="redirect_uri" id="redirect-uri">
|
<textarea name="redirect_uris" id="redirect-uris"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="field ui checkbox {{if .Err_ConfidentialClient}}error{{end}}">
|
<div class="field ui checkbox {{if .Err_ConfidentialClient}}error{{end}}">
|
||||||
<label>{{.locale.Tr "settings.oauth2_confidential_client"}}</label>
|
<label>{{.locale.Tr "settings.oauth2_confidential_client"}}</label>
|
||||||
|
|
Loading…
Reference in a new issue