Fix oauth flow and remove go-oidc library (#1063)

- Update transport to use the same from Console in IDP Auth
- Validate provided idp URL

Co-authored-by: Harshavardhana <harsha@minio.io>
Signed-off-by: Ricardo Katz <rkatz@vmware.com>
Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>

Co-authored-by: Ricardo Katz <rkatz@vmware.com>
Co-authored-by: Harshavardhana <harsha@minio.io>
This commit is contained in:
Lenin Alevski
2021-09-20 16:13:16 -07:00
committed by GitHub
parent 64e38ca8d3
commit 2b6d5e5128
28 changed files with 85 additions and 113 deletions

View File

@@ -20,6 +20,7 @@ import (
"context"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
@@ -30,7 +31,6 @@ import (
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/coreos/go-oidc"
"github.com/minio/console/pkg/auth/utils"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/oauth2"
@@ -49,6 +49,24 @@ type Config struct {
xoauth2.Config
}
// DiscoveryDoc - parses the output from openid-configuration
// for example https://accounts.google.com/.well-known/openid-configuration
type DiscoveryDoc struct {
Issuer string `json:"issuer,omitempty"`
AuthEndpoint string `json:"authorization_endpoint,omitempty"`
TokenEndpoint string `json:"token_endpoint,omitempty"`
UserInfoEndpoint string `json:"userinfo_endpoint,omitempty"`
RevocationEndpoint string `json:"revocation_endpoint,omitempty"`
JwksURI string `json:"jwks_uri,omitempty"`
ResponseTypesSupported []string `json:"response_types_supported,omitempty"`
SubjectTypesSupported []string `json:"subject_types_supported,omitempty"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"`
ScopesSupported []string `json:"scopes_supported,omitempty"`
TokenEndpointAuthMethods []string `json:"token_endpoint_auth_methods_supported,omitempty"`
ClaimsSupported []string `json:"claims_supported,omitempty"`
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
}
func (ac Config) Exchange(ctx context.Context, code string, opts ...xoauth2.AuthCodeOption) (*xoauth2.Token, error) {
return ac.Exchange(ctx, code, opts...)
}
@@ -92,7 +110,6 @@ type Provider struct {
// if enabled means that we need extrace access_token as well
UserInfo bool
oauth2Config Configuration
oidcProvider *oidc.Provider
provHTTPClient *http.Client
}
@@ -105,9 +122,9 @@ var derivedKey = func() []byte {
// NewOauth2ProviderClient instantiates a new oauth2 client using the configured credentials
// it returns a *Provider object that contains the necessary configuration to initiate an
// oauth2 authentication flow
func NewOauth2ProviderClient(ctx context.Context, scopes []string, httpClient *http.Client) (*Provider, error) {
customCtx := oidc.ClientContext(ctx, httpClient)
provider, err := oidc.NewProvider(customCtx, GetIDPURL())
func NewOauth2ProviderClient(scopes []string, httpClient *http.Client) (*Provider, error) {
ddoc, err := parseDiscoveryDoc(GetIDPURL(), httpClient)
if err != nil {
return nil, err
}
@@ -118,17 +135,20 @@ func NewOauth2ProviderClient(ctx context.Context, scopes []string, httpClient *h
}
// add "openid" scope always.
scopes = append(scopes, oidc.ScopeOpenID)
scopes = append(scopes, "openid")
client := new(Provider)
client.oauth2Config = &xoauth2.Config{
ClientID: GetIDPClientID(),
ClientSecret: GetIDPSecret(),
RedirectURL: GetIDPCallbackURL(),
Endpoint: provider.Endpoint(),
Scopes: scopes,
Endpoint: oauth2.Endpoint{
AuthURL: ddoc.AuthEndpoint,
TokenURL: ddoc.TokenEndpoint,
},
Scopes: scopes,
}
client.oidcProvider = provider
client.ClientID = GetIDPClientID()
client.UserInfo = GetIDPUserInfo()
client.provHTTPClient = httpClient
@@ -241,6 +261,32 @@ func validateOauth2State(state string) error {
return nil
}
// parseDiscoveryDoc parses a discovery doc from an OAuth provider
// into a DiscoveryDoc struct that have the correct endpoints
func parseDiscoveryDoc(ustr string, httpClient *http.Client) (DiscoveryDoc, error) {
d := DiscoveryDoc{}
req, err := http.NewRequest(http.MethodGet, ustr, nil)
if err != nil {
return d, err
}
clnt := http.Client{
Transport: httpClient.Transport,
}
resp, err := clnt.Do(req)
if err != nil {
return d, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return d, err
}
dec := json.NewDecoder(resp.Body)
if err = dec.Decode(&d); err != nil {
return d, err
}
return d, nil
}
// GetRandomStateWithHMAC computes message + hmac(message, pbkdf2(key, salt)) to be used as state during the oauth authorization
func GetRandomStateWithHMAC(length int) string {
state := utils.RandomCharString(length)

View File

@@ -21,7 +21,6 @@ import (
"net/http"
"testing"
"github.com/coreos/go-oidc"
"github.com/stretchr/testify/assert"
"golang.org/x/oauth2"
)
@@ -58,7 +57,6 @@ func TestGenerateLoginURL(t *testing.T) {
funcAssert := assert.New(t)
oauth2Provider := Provider{
oauth2Config: Oauth2configMock{},
oidcProvider: &oidc.Provider{},
}
// Test-1 : GenerateLoginURL() generates URL correctly with provided state
oauth2ConfigAuthCodeURLMock = func(state string, opts ...oauth2.AuthCodeOption) string {