Fixes to Multiple IDP support in console (#2392)

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2022-10-20 20:08:54 -05:00
committed by GitHub
parent 139e90830f
commit dab4eb7664
19 changed files with 380 additions and 112 deletions

View File

@@ -40,11 +40,12 @@ type IdentityProviderI interface {
type IdentityProvider struct {
KeyFunc oauth2.StateKeyFunc
Client *oauth2.Provider
RoleARN string
}
// VerifyIdentity will verify the user identity against the idp using the authorization code flow
func (c IdentityProvider) VerifyIdentity(ctx context.Context, code, state string) (*credentials.Credentials, error) {
return c.Client.VerifyIdentity(ctx, code, state, c.KeyFunc)
return c.Client.VerifyIdentity(ctx, code, state, c.RoleARN, c.KeyFunc)
}
// VerifyIdentityForOperator will verify the user identity against the idp using the authorization code flow
@@ -54,5 +55,5 @@ func (c IdentityProvider) VerifyIdentityForOperator(ctx context.Context, code, s
// GenerateLoginURL returns a new URL used by the user to login against the idp
func (c IdentityProvider) GenerateLoginURL() string {
return c.Client.GenerateLoginURL(c.KeyFunc)
return c.Client.GenerateLoginURL(c.KeyFunc, c.Client.IDPName)
}

View File

@@ -48,9 +48,11 @@ func (pc ProviderConfig) GetStateKeyFunc() StateKeyFunc {
}
}
type OpenIDPCfg map[string]ProviderConfig
func (pc ProviderConfig) GetARNInf() string {
return pc.RoleArn
}
var DefaultIDPConfig = "_"
type OpenIDPCfg map[string]ProviderConfig
func GetSTSEndpoint() string {
return strings.TrimSpace(env.Get(ConsoleMinIOServer, "http://localhost:9000"))

View File

@@ -29,4 +29,5 @@ const (
ConsoleIDPScopes = "CONSOLE_IDP_SCOPES"
ConsoleIDPUserInfo = "CONSOLE_IDP_USERINFO"
ConsoleIDPTokenExpiration = "CONSOLE_IDP_TOKEN_EXPIRATION"
ConsoleIDPRoleARN = "CONSOLE_IDP_ROLE_ARN"
)

View File

@@ -92,13 +92,13 @@ func (ac Config) TokenSource(ctx context.Context, t *xoauth2.Token) xoauth2.Toke
type Provider struct {
// oauth2Config is an interface configuration that contains the following fields
// Config{
// ClientID string
// IDPName string
// ClientSecret string
// RedirectURL string
// Endpoint oauth2.Endpoint
// Scopes []string
// }
// - ClientID is the public identifier for this application
// - IDPName is the public identifier for this application
// - ClientSecret is a shared secret between this application and the authorization server
// - RedirectURL is the URL to redirect users going through
// the OAuth flow, after the resource owner's URLs.
@@ -107,7 +107,7 @@ type Provider struct {
// often available via site-specific packages, such as
// google.Endpoint or github.Endpoint.
// - Scopes specifies optional requested permissions.
ClientID string
IDPName string
// if enabled means that we need extrace access_token as well
UserInfo bool
oauth2Config Configuration
@@ -178,6 +178,7 @@ func NewOauth2ProviderClient(scopes []string, r *http.Request, httpClient *http.
}
redirectURL := GetIDPCallbackURL()
if GetIDPCallbackURLDynamic() {
// dynamic redirect if set, will generate redirect URLs
// dynamically based on incoming requests.
@@ -199,7 +200,7 @@ func NewOauth2ProviderClient(scopes []string, r *http.Request, httpClient *http.
Scopes: scopes,
}
client.ClientID = GetIDPClientID()
client.IDPName = GetIDPClientID()
client.UserInfo = GetIDPUserInfo()
client.provHTTPClient = httpClient
@@ -273,7 +274,7 @@ func (o OpenIDPCfg) NewOauth2ProviderClient(name string, scopes []string, r *htt
Scopes: scopes,
}
client.ClientID = o[name].ClientID
client.IDPName = name
client.UserInfo = o[name].Userinfo
client.provHTTPClient = httpClient
return client, nil
@@ -310,9 +311,10 @@ type StateKeyFunc func() []byte
// VerifyIdentity will contact the configured IDP to the user identity based on the authorization code and state
// if the user is valid, then it will contact MinIO to get valid sts credentials based on the identity provided by the IDP
func (client *Provider) VerifyIdentity(ctx context.Context, code, state string, keyFunc StateKeyFunc) (*credentials.Credentials, error) {
func (client *Provider) VerifyIdentity(ctx context.Context, code, state, roleARN string, keyFunc StateKeyFunc) (*credentials.Credentials, error) {
// verify the provided state is valid (prevents CSRF attacks)
if err := validateOauth2State(state, keyFunc); err != nil {
fmt.Println("err1", err)
return nil, err
}
getWebTokenExpiry := func() (*credentials.WebIdentityToken, error) {
@@ -352,10 +354,12 @@ func (client *Provider) VerifyIdentity(ctx context.Context, code, state string,
return token, nil
}
stsEndpoint := GetSTSEndpoint()
sts := credentials.New(&credentials.STSWebIdentity{
Client: client.provHTTPClient,
STSEndpoint: stsEndpoint,
GetWebIDTokenExpiry: getWebTokenExpiry,
RoleARN: roleARN,
})
return sts, nil
}
@@ -439,10 +443,34 @@ func GetRandomStateWithHMAC(length int, keyFunc StateKeyFunc) string {
return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", state, hmac)))
}
type LoginURLParams struct {
State string `json:"state"`
IDPName string `json:"idp_name"`
}
// GenerateLoginURL returns a new login URL based on the configured IDP
func (client *Provider) GenerateLoginURL(keyFunc StateKeyFunc) string {
func (client *Provider) GenerateLoginURL(keyFunc StateKeyFunc, iDPName string) string {
// generates random state and sign it using HMAC256
state := GetRandomStateWithHMAC(25, keyFunc)
loginURL := client.oauth2Config.AuthCodeURL(state)
configureID := "_"
if iDPName != "" {
configureID = iDPName
}
lgParams := LoginURLParams{
State: state,
IDPName: configureID,
}
jsonEnc, err := json.Marshal(lgParams)
if err != nil {
return ""
}
stEncode := base64.StdEncoding.EncodeToString(jsonEnc)
loginURL := client.oauth2Config.AuthCodeURL(stEncode)
return strings.TrimSpace(loginURL)
}

View File

@@ -66,6 +66,6 @@ func TestGenerateLoginURL(t *testing.T) {
// a non-empty string
return state
}
url := oauth2Provider.GenerateLoginURL(DefaultDerivedKey)
url := oauth2Provider.GenerateLoginURL(DefaultDerivedKey, "testIDP")
funcAssert.NotEqual("", url)
}