OIDC: allow to debug the received id_token
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
a0bbcf6ebb
commit
e6bfbcd489
8 changed files with 35 additions and 5 deletions
|
@ -122,6 +122,7 @@ var (
|
|||
ImplicitRoles: false,
|
||||
Scopes: []string{"openid", "profile", "email"},
|
||||
CustomFields: []string{},
|
||||
Debug: false,
|
||||
},
|
||||
Security: httpd.SecurityConf{
|
||||
Enabled: false,
|
||||
|
@ -1437,6 +1438,12 @@ func getHTTPDOIDCFromEnv(idx int) (httpd.OIDC, bool) {
|
|||
isSet = true
|
||||
}
|
||||
|
||||
debug, ok := lookupBoolFromEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__OIDC__DEBUG", idx))
|
||||
if ok {
|
||||
result.Debug = debug
|
||||
isSet = true
|
||||
}
|
||||
|
||||
return result, isSet
|
||||
}
|
||||
|
||||
|
|
|
@ -1055,6 +1055,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
|
|||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__SCOPES", "openid")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__IMPLICIT_ROLES", "1")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__CUSTOM_FIELDS", "field1,field2")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__DEBUG", "1")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__ENABLED", "true")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__ALLOWED_HOSTS", "*.example.com,*.example.net")
|
||||
os.Setenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__ALLOWED_HOSTS_ARE_REGEX", "1")
|
||||
|
@ -1121,6 +1122,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
|
|||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__SCOPES")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__IMPLICIT_ROLES")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__CUSTOM_FIELDS")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__DEBUG")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__ENABLED")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__ALLOWED_HOSTS")
|
||||
os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__ALLOWED_HOSTS_ARE_REGEX")
|
||||
|
@ -1170,6 +1172,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
|
|||
require.False(t, bindings[0].Security.Enabled)
|
||||
require.Equal(t, 0, bindings[0].ClientIPHeaderDepth)
|
||||
require.Len(t, bindings[0].OIDC.Scopes, 3)
|
||||
require.False(t, bindings[0].OIDC.Debug)
|
||||
require.Equal(t, 8000, bindings[1].Port)
|
||||
require.Equal(t, "127.0.0.1", bindings[1].Address)
|
||||
require.False(t, bindings[1].EnableHTTPS)
|
||||
|
@ -1182,6 +1185,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
|
|||
require.Equal(t, 1, bindings[1].HideLoginURL)
|
||||
require.Empty(t, bindings[1].OIDC.ClientID)
|
||||
require.Len(t, bindings[1].OIDC.Scopes, 3)
|
||||
require.False(t, bindings[1].OIDC.Debug)
|
||||
require.False(t, bindings[1].Security.Enabled)
|
||||
require.Equal(t, "Web Admin", bindings[1].Branding.WebAdmin.Name)
|
||||
require.Equal(t, "WebClient", bindings[1].Branding.WebClient.ShortName)
|
||||
|
@ -1219,6 +1223,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
|
|||
require.Len(t, bindings[2].OIDC.CustomFields, 2)
|
||||
require.Equal(t, "field1", bindings[2].OIDC.CustomFields[0])
|
||||
require.Equal(t, "field2", bindings[2].OIDC.CustomFields[1])
|
||||
require.True(t, bindings[2].OIDC.Debug)
|
||||
require.True(t, bindings[2].Security.Enabled)
|
||||
require.Len(t, bindings[2].Security.AllowedHosts, 2)
|
||||
require.Equal(t, "*.example.com", bindings[2].Security.AllowedHosts[0])
|
||||
|
|
|
@ -280,6 +280,7 @@ The configuration file contains the following sections:
|
|||
- `role_field`, string. Defines the optional ID token claims field to map to a SFTPGo role. If the defined ID token claims field is set to `admin` the authenticated user is mapped to an SFTPGo admin. You don't need to specify this field if you want to use OpenID only for the Web Client UI. Default: blank.
|
||||
- `implicit_roles`, boolean. If set, the `role_field` is ignored and the SFTPGo role is assumed based on the login link used. Default: `false`.
|
||||
- `custom_fields`, list of strings. Custom token claims fields to pass to the pre-login hook. Default: empty.
|
||||
- `debug`, boolean. If set, the received id tokens will be logged at debug level. Default: `false`.
|
||||
- `security`, struct. Defines security headers to add to HTTP responses and allows to restrict allowed hosts. The following parameters are supported:
|
||||
- `enabled`, boolean. Set to `true` to enable security configurations. Default: `false`.
|
||||
- `allowed_hosts`, list of strings. Fully qualified domain names that are allowed. An empty list allows any and all host names. Default: empty.
|
||||
|
|
2
go.mod
2
go.mod
|
@ -68,7 +68,7 @@ require (
|
|||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
golang.org/x/net v0.0.0-20220708220712-1185a9018129
|
||||
golang.org/x/oauth2 v0.0.0-20220718184931-c8730f7fcb92
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8
|
||||
golang.org/x/sys v0.0.0-20220721230656-c6bc011c0c49
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858
|
||||
google.golang.org/api v0.88.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
|
|
4
go.sum
4
go.sum
|
@ -970,8 +970,8 @@ golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220721230656-c6bc011c0c49 h1:TMjZDarEwf621XDryfitp/8awEhiZNiwgphKlTMGRIg=
|
||||
golang.org/x/sys v0.0.0-20220721230656-c6bc011c0c49/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
|
|
@ -89,7 +89,10 @@ type OIDC struct {
|
|||
// Refer to your OAuth provider documentation for more information about this
|
||||
Scopes []string `json:"scopes" mapstructure:"scopes"`
|
||||
// Custom token claims fields to pass to the pre-login hook
|
||||
CustomFields []string `json:"custom_fields" mapstructure:"custom_fields"`
|
||||
CustomFields []string `json:"custom_fields" mapstructure:"custom_fields"`
|
||||
// Debug enables the OIDC debug mode. In debug mode, the received id_token will be logged
|
||||
// at the debug level
|
||||
Debug bool `json:"debug" mapstructure:"debug"`
|
||||
provider *oidc.Provider
|
||||
verifier OIDCTokenVerifier
|
||||
providerLogoutURL string
|
||||
|
@ -477,6 +480,16 @@ func (s *httpdServer) oidcLoginRedirect(w http.ResponseWriter, r *http.Request,
|
|||
oidc.Nonce(pendingAuth.Nonce)), http.StatusFound)
|
||||
}
|
||||
|
||||
func (s *httpdServer) debugTokenClaims(claims map[string]any, rawIDToken string) {
|
||||
if s.binding.OIDC.Debug {
|
||||
if claims == nil {
|
||||
logger.Debug(logSender, "", "raw id token %q", rawIDToken)
|
||||
} else {
|
||||
logger.Debug(logSender, "", "raw id token %q, parsed claims %+v", rawIDToken, claims)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *httpdServer) handleOIDCRedirect(w http.ResponseWriter, r *http.Request) {
|
||||
state := r.URL.Query().Get("state")
|
||||
authReq, err := oidcMgr.getPendingAuth(state)
|
||||
|
@ -516,6 +529,7 @@ func (s *httpdServer) handleOIDCRedirect(w http.ResponseWriter, r *http.Request)
|
|||
doRedirect()
|
||||
return
|
||||
}
|
||||
s.debugTokenClaims(nil, rawIDToken)
|
||||
idToken, err := s.binding.OIDC.verifier.Verify(ctx, rawIDToken)
|
||||
if err != nil {
|
||||
logger.Debug(logSender, "", "failed to verify oidc token: %v", err)
|
||||
|
@ -541,6 +555,7 @@ func (s *httpdServer) handleOIDCRedirect(w http.ResponseWriter, r *http.Request)
|
|||
doLogout(rawIDToken)
|
||||
return
|
||||
}
|
||||
s.debugTokenClaims(claims, rawIDToken)
|
||||
token := oidcToken{
|
||||
AccessToken: oauth2Token.AccessToken,
|
||||
TokenType: oauth2Token.TokenType,
|
||||
|
|
|
@ -1380,6 +1380,7 @@ func getTestOIDCServer() *httpdServer {
|
|||
ImplicitRoles: false,
|
||||
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
|
||||
CustomFields: nil,
|
||||
Debug: true,
|
||||
},
|
||||
},
|
||||
enableWebAdmin: true,
|
||||
|
|
|
@ -266,7 +266,8 @@
|
|||
"username_field": "",
|
||||
"role_field": "",
|
||||
"implicit_roles": false,
|
||||
"custom_fields": []
|
||||
"custom_fields": [],
|
||||
"debug": false
|
||||
},
|
||||
"security": {
|
||||
"enabled": false,
|
||||
|
|
Loading…
Reference in a new issue