|
|
|
|
@@ -16,19 +16,24 @@ import (
|
|
|
|
|
"imuslab.com/zoraxy/mod/utils"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// DefaultOAuth2ConfigCacheTime defines the default cache duration for OAuth2 configuration
|
|
|
|
|
DefaultOAuth2ConfigCacheTime = 60 * time.Second
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type OAuth2RouterOptions struct {
|
|
|
|
|
OAuth2ServerURL string //The URL of the OAuth 2.0 server server
|
|
|
|
|
OAuth2TokenURL string //The URL of the OAuth 2.0 token server
|
|
|
|
|
OAuth2ClientId string //The client id for OAuth 2.0 Application
|
|
|
|
|
OAuth2ClientSecret string //The client secret for OAuth 2.0 Application
|
|
|
|
|
OAuth2WellKnownUrl string //The well-known url for OAuth 2.0 server
|
|
|
|
|
OAuth2UserInfoUrl string //The URL of the OAuth 2.0 user info endpoint
|
|
|
|
|
OAuth2Scopes string //The scopes for OAuth 2.0 Application
|
|
|
|
|
OAuth2CodeChallengeMethod string //The authorization code challenge method
|
|
|
|
|
Logger *logger.Logger
|
|
|
|
|
Database *database.Database
|
|
|
|
|
OAuth2ConfigCacheTTL *time.Duration
|
|
|
|
|
OAuth2ConfigCache *ttlcache.Cache[string, *oauth2.Config]
|
|
|
|
|
OAuth2ServerURL string //The URL of the OAuth 2.0 server server
|
|
|
|
|
OAuth2TokenURL string //The URL of the OAuth 2.0 token server
|
|
|
|
|
OAuth2ClientId string //The client id for OAuth 2.0 Application
|
|
|
|
|
OAuth2ClientSecret string //The client secret for OAuth 2.0 Application
|
|
|
|
|
OAuth2WellKnownUrl string //The well-known url for OAuth 2.0 server
|
|
|
|
|
OAuth2UserInfoUrl string //The URL of the OAuth 2.0 user info endpoint
|
|
|
|
|
OAuth2Scopes string //The scopes for OAuth 2.0 Application
|
|
|
|
|
OAuth2CodeChallengeMethod string //The authorization code challenge method
|
|
|
|
|
OAuth2ConfigurationCacheTime *time.Duration
|
|
|
|
|
Logger *logger.Logger
|
|
|
|
|
Database *database.Database
|
|
|
|
|
OAuth2ConfigCache *ttlcache.Cache[string, *oauth2.Config]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type OIDCDiscoveryDocument struct {
|
|
|
|
|
@@ -64,13 +69,20 @@ func NewOAuth2Router(options *OAuth2RouterOptions) *OAuth2Router {
|
|
|
|
|
options.Database.Read("oauth2", "oauth2UserInfoUrl", &options.OAuth2UserInfoUrl)
|
|
|
|
|
options.Database.Read("oauth2", "oauth2CodeChallengeMethod", &options.OAuth2CodeChallengeMethod)
|
|
|
|
|
options.Database.Read("oauth2", "oauth2Scopes", &options.OAuth2Scopes)
|
|
|
|
|
options.Database.Read("oauth2", "oauth2ConfigurationCacheTime", &options.OAuth2ConfigurationCacheTime)
|
|
|
|
|
|
|
|
|
|
ar := &OAuth2Router{
|
|
|
|
|
options: options,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if options.OAuth2ConfigurationCacheTime == nil ||
|
|
|
|
|
options.OAuth2ConfigurationCacheTime.Seconds() == 0 {
|
|
|
|
|
cacheTime := DefaultOAuth2ConfigCacheTime
|
|
|
|
|
options.OAuth2ConfigurationCacheTime = &cacheTime
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
options.OAuth2ConfigCache = ttlcache.New[string, *oauth2.Config](
|
|
|
|
|
ttlcache.WithTTL[string, *oauth2.Config](*options.OAuth2ConfigCacheTTL),
|
|
|
|
|
ttlcache.WithTTL[string, *oauth2.Config](*options.OAuth2ConfigurationCacheTime),
|
|
|
|
|
)
|
|
|
|
|
go options.OAuth2ConfigCache.Start()
|
|
|
|
|
|
|
|
|
|
@@ -94,14 +106,15 @@ func (ar *OAuth2Router) HandleSetOAuth2Settings(w http.ResponseWriter, r *http.R
|
|
|
|
|
func (ar *OAuth2Router) handleSetOAuthSettingsGET(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
//Return the current settings
|
|
|
|
|
js, _ := json.Marshal(map[string]interface{}{
|
|
|
|
|
"oauth2WellKnownUrl": ar.options.OAuth2WellKnownUrl,
|
|
|
|
|
"oauth2ServerUrl": ar.options.OAuth2ServerURL,
|
|
|
|
|
"oauth2TokenUrl": ar.options.OAuth2TokenURL,
|
|
|
|
|
"oauth2UserInfoUrl": ar.options.OAuth2UserInfoUrl,
|
|
|
|
|
"oauth2Scopes": ar.options.OAuth2Scopes,
|
|
|
|
|
"oauth2ClientSecret": ar.options.OAuth2ClientSecret,
|
|
|
|
|
"oauth2ClientId": ar.options.OAuth2ClientId,
|
|
|
|
|
"oauth2CodeChallengeMethod": ar.options.OAuth2CodeChallengeMethod,
|
|
|
|
|
"oauth2WellKnownUrl": ar.options.OAuth2WellKnownUrl,
|
|
|
|
|
"oauth2ServerUrl": ar.options.OAuth2ServerURL,
|
|
|
|
|
"oauth2TokenUrl": ar.options.OAuth2TokenURL,
|
|
|
|
|
"oauth2UserInfoUrl": ar.options.OAuth2UserInfoUrl,
|
|
|
|
|
"oauth2Scopes": ar.options.OAuth2Scopes,
|
|
|
|
|
"oauth2ClientSecret": ar.options.OAuth2ClientSecret,
|
|
|
|
|
"oauth2ClientId": ar.options.OAuth2ClientId,
|
|
|
|
|
"oauth2CodeChallengeMethod": ar.options.OAuth2CodeChallengeMethod,
|
|
|
|
|
"oauth2ConfigurationCacheTime": ar.options.OAuth2ConfigurationCacheTime.String(),
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
utils.SendJSONResponse(w, string(js))
|
|
|
|
|
@@ -110,6 +123,7 @@ func (ar *OAuth2Router) handleSetOAuthSettingsGET(w http.ResponseWriter, r *http
|
|
|
|
|
func (ar *OAuth2Router) handleSetOAuthSettingsPOST(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
//Update the settings
|
|
|
|
|
var oauth2ServerUrl, oauth2TokenURL, oauth2Scopes, oauth2UserInfoUrl, oauth2CodeChallengeMethod string
|
|
|
|
|
var oauth2ConfigurationCacheTime *time.Duration
|
|
|
|
|
|
|
|
|
|
oauth2ClientId, err := utils.PostPara(r, "oauth2ClientId")
|
|
|
|
|
if err != nil {
|
|
|
|
|
@@ -129,8 +143,14 @@ func (ar *OAuth2Router) handleSetOAuthSettingsPOST(w http.ResponseWriter, r *htt
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oauth2WellKnownUrl, err := utils.PostPara(r, "oauth2WellKnownUrl")
|
|
|
|
|
oauth2ConfigurationCacheTime, err = utils.PostDuration(r, "oauth2ConfigurationCacheTime")
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.SendErrorResponse(w, "oauth2ConfigurationCacheTime not found")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oauth2WellKnownUrl, err := utils.PostPara(r, "oauth2WellKnownUrl")
|
|
|
|
|
if err != nil || oauth2WellKnownUrl == "" {
|
|
|
|
|
oauth2ServerUrl, err = utils.PostPara(r, "oauth2ServerUrl")
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.SendErrorResponse(w, "oauth2ServerUrl not found")
|
|
|
|
|
@@ -167,6 +187,7 @@ func (ar *OAuth2Router) handleSetOAuthSettingsPOST(w http.ResponseWriter, r *htt
|
|
|
|
|
ar.options.OAuth2ClientSecret = oauth2ClientSecret
|
|
|
|
|
ar.options.OAuth2Scopes = oauth2Scopes
|
|
|
|
|
ar.options.OAuth2CodeChallengeMethod = oauth2CodeChallengeMethod
|
|
|
|
|
ar.options.OAuth2ConfigurationCacheTime = oauth2ConfigurationCacheTime
|
|
|
|
|
|
|
|
|
|
//Write changes to database
|
|
|
|
|
ar.options.Database.Write("oauth2", "oauth2WellKnownUrl", oauth2WellKnownUrl)
|
|
|
|
|
@@ -177,6 +198,7 @@ func (ar *OAuth2Router) handleSetOAuthSettingsPOST(w http.ResponseWriter, r *htt
|
|
|
|
|
ar.options.Database.Write("oauth2", "oauth2ClientSecret", oauth2ClientSecret)
|
|
|
|
|
ar.options.Database.Write("oauth2", "oauth2Scopes", oauth2Scopes)
|
|
|
|
|
ar.options.Database.Write("oauth2", "oauth2CodeChallengeMethod", oauth2CodeChallengeMethod)
|
|
|
|
|
ar.options.Database.Write("oauth2", "oauth2ConfigurationCacheTime", oauth2ConfigurationCacheTime)
|
|
|
|
|
|
|
|
|
|
// Flush caches
|
|
|
|
|
ar.options.OAuth2ConfigCache.DeleteAll()
|
|
|
|
|
@@ -202,6 +224,7 @@ func (ar *OAuth2Router) handleSetOAuthSettingsDELETE(w http.ResponseWriter, r *h
|
|
|
|
|
ar.options.Database.Delete("oauth2", "oauth2ClientSecret")
|
|
|
|
|
ar.options.Database.Delete("oauth2", "oauth2Scopes")
|
|
|
|
|
ar.options.Database.Delete("oauth2", "oauth2CodeChallengeMethod")
|
|
|
|
|
ar.options.Database.Delete("oauth2", "oauth2ConfigurationCacheTime")
|
|
|
|
|
|
|
|
|
|
utils.SendOK(w)
|
|
|
|
|
}
|
|
|
|
|
@@ -273,7 +296,7 @@ func (ar *OAuth2Router) HandleOAuth2Auth(w http.ResponseWriter, r *http.Request)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reqUrl := scheme + "://" + r.Host + r.RequestURI
|
|
|
|
|
oauthConfigCache, status := ar.options.OAuth2ConfigCache.GetOrSetFunc(r.Host, func() *oauth2.Config {
|
|
|
|
|
oauthConfigCache, _ := ar.options.OAuth2ConfigCache.GetOrSetFunc(r.Host, func() *oauth2.Config {
|
|
|
|
|
oauthConfig, err := ar.newOAuth2Conf(scheme + "://" + r.Host + callbackPrefix)
|
|
|
|
|
if err != nil {
|
|
|
|
|
ar.options.Logger.PrintAndLog("OAuth2Router", "Failed to fetch OIDC configuration:", err)
|
|
|
|
|
|