Skip to content

Commit

Permalink
Remove RedirectURL parameter from auth code flow (#13565)
Browse files Browse the repository at this point in the history
To align with the MSAL implementation which relies on the native client
redirect URL.
  • Loading branch information
jhendrixMSFT committed Nov 16, 2020
1 parent 13c7f96 commit 733cb9b
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 21 deletions.
11 changes: 6 additions & 5 deletions sdk/azidentity/aad_identity_client.go
Expand Up @@ -385,7 +385,7 @@ func (c *aadIdentityClient) authenticateInteractiveBrowser(ctx context.Context,
if err != nil {
return nil, err
}
return c.authenticateAuthCode(ctx, tenantID, clientID, cfg.authCode, clientSecret, cfg.redirectURI, scopes)
return c.authenticateAuthCode(ctx, tenantID, clientID, cfg.authCode, clientSecret, scopes)
}

// authenticateAuthCode requests an Access Token with the authorization code and returns the token or an error in case of authentication failure.
Expand All @@ -396,8 +396,8 @@ func (c *aadIdentityClient) authenticateInteractiveBrowser(ctx context.Context,
// clientSecret: Gets the client secret that was generated for the App Registration used to authenticate the client.
// redirectURI: The redirect URI that was used to request the authorization code. Must be the same URI that is configured for the App Registration.
// scopes: The scopes required for the token
func (c *aadIdentityClient) authenticateAuthCode(ctx context.Context, tenantID string, clientID string, authCode string, clientSecret string, redirectURI string, scopes []string) (*azcore.AccessToken, error) {
req, err := c.createAuthorizationCodeAuthRequest(ctx, tenantID, clientID, authCode, clientSecret, redirectURI, scopes)
func (c *aadIdentityClient) authenticateAuthCode(ctx context.Context, tenantID string, clientID string, authCode string, clientSecret string, scopes []string) (*azcore.AccessToken, error) {
req, err := c.createAuthorizationCodeAuthRequest(ctx, tenantID, clientID, authCode, clientSecret, scopes)
if err != nil {
return nil, err
}
Expand All @@ -415,14 +415,15 @@ func (c *aadIdentityClient) authenticateAuthCode(ctx context.Context, tenantID s
}

// createAuthorizationCodeAuthRequest creates a request for an Access Token for authorization_code grant types.
func (c *aadIdentityClient) createAuthorizationCodeAuthRequest(ctx context.Context, tenantID string, clientID string, authCode string, clientSecret string, redirectURI string, scopes []string) (*azcore.Request, error) {
func (c *aadIdentityClient) createAuthorizationCodeAuthRequest(ctx context.Context, tenantID string, clientID string, authCode string, clientSecret string, scopes []string) (*azcore.Request, error) {
data := url.Values{}
data.Set(qpGrantType, "authorization_code")
data.Set(qpClientID, clientID)
if clientSecret != "" {
data.Set(qpClientSecret, clientSecret) // only for web apps
}
data.Set(qpRedirectURI, redirectURI)
// similar to MSAL, we use a hard-coded redirect URI here as we never actually redirect to it
data.Set(qpRedirectURI, "https://login.microsoftonline.com/common/oauth2/nativeclient")
data.Set(qpScope, strings.Join(scopes, " "))
data.Set(qpCode, authCode)
dataEncoded := data.Encode()
Expand Down
8 changes: 3 additions & 5 deletions sdk/azidentity/authorization_code_credential.go
Expand Up @@ -43,16 +43,14 @@ type AuthorizationCodeCredential struct {
clientID string // Gets the client (application) ID of the service principal
authCode string // The authorization code received from the authorization code flow. The authorization code must not have been used to obtain another token.
clientSecret string // Gets the client secret that was generated for the App Registration used to authenticate the client.
redirectURI string // The redirect URI that was used to request the authorization code. Must be the same URI that is configured for the App Registration.
}

// NewAuthorizationCodeCredential constructs a new AuthorizationCodeCredential with the details needed to authenticate against Azure Active Directory with an authorization code.
// tenantID: The Azure Active Directory tenant (directory) ID of the service principal.
// clientID: The client (application) ID of the service principal.
// authCode: The authorization code received from the authorization code flow. The authorization code must not have been used to obtain another token.
// redirectURL: The redirect URL that was used to request the authorization code. Must be the same URL that is configured for the App Registration.
// options: Manage the configuration of the requests sent to Azure Active Directory, they can also include a client secret for web app authentication.
func NewAuthorizationCodeCredential(tenantID string, clientID string, authCode string, redirectURL string, options *AuthorizationCodeCredentialOptions) (*AuthorizationCodeCredential, error) {
func NewAuthorizationCodeCredential(tenantID string, clientID string, authCode string, options *AuthorizationCodeCredentialOptions) (*AuthorizationCodeCredential, error) {
if !validTenantID(tenantID) {
return nil, &CredentialUnavailableError{credentialType: "Authorization Code Credential", message: tenantIDValidationErr}
}
Expand All @@ -68,15 +66,15 @@ func NewAuthorizationCodeCredential(tenantID string, clientID string, authCode s
if err != nil {
return nil, err
}
return &AuthorizationCodeCredential{tenantID: tenantID, clientID: clientID, authCode: authCode, clientSecret: options.ClientSecret, redirectURI: redirectURL, client: c}, nil
return &AuthorizationCodeCredential{tenantID: tenantID, clientID: clientID, authCode: authCode, clientSecret: options.ClientSecret, client: c}, nil
}

// GetToken obtains a token from Azure Active Directory, using the specified authorization code to authenticate.
// ctx: Context used to control the request lifetime.
// opts: TokenRequestOptions contains the list of scopes for which the token will have access.
// Returns an AccessToken which can be used to authenticate service client calls.
func (c *AuthorizationCodeCredential) GetToken(ctx context.Context, opts azcore.TokenRequestOptions) (*azcore.AccessToken, error) {
tk, err := c.client.authenticateAuthCode(ctx, c.tenantID, c.clientID, c.authCode, c.clientSecret, c.redirectURI, opts.Scopes)
tk, err := c.client.authenticateAuthCode(ctx, c.tenantID, c.clientID, c.authCode, c.clientSecret, opts.Scopes)
if err != nil {
addGetTokenFailureLogs("Authorization Code Credential", err, true)
return nil, err
Expand Down
18 changes: 7 additions & 11 deletions sdk/azidentity/authorization_code_credential_test.go
Expand Up @@ -16,12 +16,11 @@ import (
)

const (
testAuthCode = "12345"
testRedirectURI = "http://localhost"
testAuthCode = "12345"
)

func TestAuthorizationCodeCredential_InvalidTenantID(t *testing.T) {
cred, err := NewAuthorizationCodeCredential(badTenantID, clientID, testAuthCode, testRedirectURI, nil)
cred, err := NewAuthorizationCodeCredential(badTenantID, clientID, testAuthCode, nil)
if err == nil {
t.Fatal("Expected an error but received none")
}
Expand All @@ -35,11 +34,11 @@ func TestAuthorizationCodeCredential_InvalidTenantID(t *testing.T) {
}

func TestAuthorizationCodeCredential_CreateAuthRequestSuccess(t *testing.T) {
cred, err := NewAuthorizationCodeCredential(tenantID, clientID, testAuthCode, testRedirectURI, nil)
cred, err := NewAuthorizationCodeCredential(tenantID, clientID, testAuthCode, nil)
if err != nil {
t.Fatalf("Unable to create credential. Received: %v", err)
}
req, err := cred.client.createAuthorizationCodeAuthRequest(context.Background(), cred.tenantID, cred.clientID, cred.authCode, cred.clientSecret, cred.redirectURI, []string{scope})
req, err := cred.client.createAuthorizationCodeAuthRequest(context.Background(), cred.tenantID, cred.clientID, cred.authCode, cred.clientSecret, []string{scope})
if err != nil {
t.Fatalf("Unexpectedly received an error: %v", err)
}
Expand All @@ -64,9 +63,6 @@ func TestAuthorizationCodeCredential_CreateAuthRequestSuccess(t *testing.T) {
if reqQueryParams[qpCode][0] != testAuthCode {
t.Fatal("Unexpected authorization code")
}
if reqQueryParams[qpRedirectURI][0] != testRedirectURI {
t.Fatal("Unexpected redirectURI")
}
if req.Request.URL.Host != defaultTestAuthorityHost {
t.Fatal("Unexpected default authority host")
}
Expand All @@ -83,7 +79,7 @@ func TestAuthorizationCodeCredential_GetTokenSuccess(t *testing.T) {
options.ClientSecret = secret
options.AuthorityHost = srv.URL()
options.HTTPClient = srv
cred, err := NewAuthorizationCodeCredential(tenantID, clientID, testAuthCode, testRedirectURI, &options)
cred, err := NewAuthorizationCodeCredential(tenantID, clientID, testAuthCode, &options)
if err != nil {
t.Fatalf("Unable to create credential. Received: %v", err)
}
Expand All @@ -101,7 +97,7 @@ func TestAuthorizationCodeCredential_GetTokenInvalidCredentials(t *testing.T) {
options.ClientSecret = secret
options.AuthorityHost = srv.URL()
options.HTTPClient = srv
cred, err := NewAuthorizationCodeCredential(tenantID, clientID, testAuthCode, testRedirectURI, &options)
cred, err := NewAuthorizationCodeCredential(tenantID, clientID, testAuthCode, &options)
if err != nil {
t.Fatalf("Unable to create credential. Received: %v", err)
}
Expand Down Expand Up @@ -150,7 +146,7 @@ func TestAuthorizationCodeCredential_GetTokenUnexpectedJSON(t *testing.T) {
options.ClientSecret = secret
options.AuthorityHost = srv.URL()
options.HTTPClient = srv
cred, err := NewAuthorizationCodeCredential(tenantID, clientID, testRedirectURI, testRedirectURI, &options)
cred, err := NewAuthorizationCodeCredential(tenantID, clientID, testAuthCode, &options)
if err != nil {
t.Fatalf("Failed to create the credential")
}
Expand Down

0 comments on commit 733cb9b

Please sign in to comment.