forked from casdoor/casdoor
feat: add Provider.CustomLogoutUrl field
This commit is contained in:
@@ -374,6 +374,10 @@ func (c *ApiController) Logout() {
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve application and token before clearing the session
|
||||
application := c.GetSessionApplication()
|
||||
sessionToken := c.GetSessionToken()
|
||||
|
||||
c.ClearUserSession()
|
||||
c.ClearTokenSession()
|
||||
|
||||
@@ -382,7 +386,9 @@ func (c *ApiController) Logout() {
|
||||
return
|
||||
}
|
||||
|
||||
application := c.GetSessionApplication()
|
||||
// Propagate logout to external Custom OAuth2 providers
|
||||
object.InvokeCustomProviderLogout(application, sessionToken)
|
||||
|
||||
if application == nil || application.Name == "app-built-in" || application.HomepageUrl == "" {
|
||||
c.ResponseOk(user)
|
||||
return
|
||||
@@ -427,6 +433,9 @@ func (c *ApiController) Logout() {
|
||||
return
|
||||
}
|
||||
|
||||
// Propagate logout to external Custom OAuth2 providers
|
||||
object.InvokeCustomProviderLogout(application, accessToken)
|
||||
|
||||
if redirectUri == "" {
|
||||
c.ResponseOk()
|
||||
return
|
||||
@@ -469,6 +478,10 @@ func (c *ApiController) SsoLogout() {
|
||||
logoutAll := c.Ctx.Input.Query("logoutAll")
|
||||
logoutAllSessions := logoutAll == "" || logoutAll == "true" || logoutAll == "1"
|
||||
|
||||
// Retrieve application and token before clearing the session
|
||||
ssoApplication := c.GetSessionApplication()
|
||||
ssoSessionToken := c.GetSessionToken()
|
||||
|
||||
c.ClearUserSession()
|
||||
c.ClearTokenSession()
|
||||
owner, username, err := util.GetOwnerAndNameFromIdWithError(user)
|
||||
@@ -548,6 +561,9 @@ func (c *ApiController) SsoLogout() {
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate logout to external Custom OAuth2 providers
|
||||
object.InvokeCustomProviderLogout(ssoApplication, ssoSessionToken)
|
||||
|
||||
c.ResponseOk()
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ package object
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@@ -48,6 +50,7 @@ type Provider struct {
|
||||
CustomAuthUrl string `xorm:"varchar(200)" json:"customAuthUrl"`
|
||||
CustomTokenUrl string `xorm:"varchar(200)" json:"customTokenUrl"`
|
||||
CustomUserInfoUrl string `xorm:"varchar(200)" json:"customUserInfoUrl"`
|
||||
CustomLogoutUrl string `xorm:"varchar(200)" json:"customLogoutUrl"`
|
||||
CustomLogo string `xorm:"varchar(200)" json:"customLogo"`
|
||||
Scopes string `xorm:"varchar(100)" json:"scopes"`
|
||||
UserMapping map[string]string `xorm:"varchar(500)" json:"userMapping"`
|
||||
@@ -686,3 +689,43 @@ func GetLogProviderFromProvider(provider *Provider) (log.LogProvider, error) {
|
||||
|
||||
return log.GetLogProvider(provider.Type, provider.Host, provider.Port, provider.Title)
|
||||
}
|
||||
|
||||
// InvokeCustomProviderLogout iterates through the application's Custom OAuth2 providers
|
||||
// and calls their logout endpoint (if configured) to terminate the upstream session.
|
||||
func InvokeCustomProviderLogout(application *Application, accessToken string) {
|
||||
if application == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, providerItem := range application.Providers {
|
||||
provider := providerItem.Provider
|
||||
if provider == nil || provider.Category != "OAuth" || !strings.HasPrefix(provider.Type, "Custom") {
|
||||
continue
|
||||
}
|
||||
if provider.CustomLogoutUrl == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
go callProviderLogoutUrl(provider, accessToken)
|
||||
}
|
||||
}
|
||||
|
||||
// callProviderLogoutUrl sends a logout/token-revocation request to the provider's logout URL.
|
||||
// Supports RFC 7009 token revocation and Keycloak-style end_session endpoints.
|
||||
func callProviderLogoutUrl(provider *Provider, accessToken string) {
|
||||
params := url.Values{}
|
||||
params.Set("token", accessToken)
|
||||
params.Set("client_id", provider.ClientId)
|
||||
params.Set("client_secret", provider.ClientSecret)
|
||||
|
||||
resp, err := http.PostForm(provider.CustomLogoutUrl, params)
|
||||
if err != nil {
|
||||
util.LogWarning(nil, "InvokeCustomProviderLogout: failed to call logout URL %s for provider %s: %v", provider.CustomLogoutUrl, provider.Name, err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
util.LogWarning(nil, "InvokeCustomProviderLogout: logout URL %s returned status %d for provider %s", provider.CustomLogoutUrl, resp.StatusCode, provider.Name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +164,16 @@ export function renderOAuthProviderFields(provider, updateProviderField, renderU
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Logout URL"), i18next.t("provider:Logout URL - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={provider.customLogoutUrl} onChange={e => {
|
||||
updateProviderField("customLogoutUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Enable PKCE"), i18next.t("provider:Enable PKCE - Tooltip"))} :
|
||||
|
||||
Reference in New Issue
Block a user