From 4b8d5d0f0923cd4e8bbc2b66a2b0e08a9637fa1a Mon Sep 17 00:00:00 2001 From: Joel Hendrix Date: Thu, 4 Mar 2021 13:37:32 -0800 Subject: [PATCH 1/2] Make redirect URI a required parameter for auth code flow Don't hard-code the nativeclient redirect URI. Make the auth code a parameter for the public client (the same was already done for confidential client). --- apps/confidential/confidential.go | 13 +++++----- apps/confidential/confidential_test.go | 2 +- apps/internal/base/base.go | 13 +++++----- apps/public/public.go | 34 ++++++-------------------- 4 files changed, 23 insertions(+), 39 deletions(-) diff --git a/apps/confidential/confidential.go b/apps/confidential/confidential.go index d14ab2c0..9cdcf637 100644 --- a/apps/confidential/confidential.go +++ b/apps/confidential/confidential.go @@ -311,18 +311,19 @@ func WithChallenge(challenge string) AcquireTokenByAuthCodeOption { } // AcquireTokenByAuthCode is a request to acquire a security token from the authority, using an authorization code. -func (cca Client) AcquireTokenByAuthCode(ctx context.Context, code string, scopes []string, options ...AcquireTokenByAuthCodeOption) (AuthResult, error) { +func (cca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redirectURI string, scopes []string, options ...AcquireTokenByAuthCodeOption) (AuthResult, error) { opts := AcquireTokenByAuthCodeOptions{} for _, o := range options { o(&opts) } params := base.AcquireTokenAuthCodeParameters{ - Scopes: scopes, - Code: code, - Challenge: opts.Challenge, - AppType: accesstokens.ATConfidential, - Credential: cca.cred, // This setting differs from public.Client.AcquireTokenByAuthCode + Scopes: scopes, + Code: code, + Challenge: opts.Challenge, + AppType: accesstokens.ATConfidential, + Credential: cca.cred, // This setting differs from public.Client.AcquireTokenByAuthCode + RedirectURI: redirectURI, } return cca.base.AcquireTokenByAuthCode(ctx, params) diff --git a/apps/confidential/confidential_test.go b/apps/confidential/confidential_test.go index bb702f2c..ea8347cb 100644 --- a/apps/confidential/confidential_test.go +++ b/apps/confidential/confidential_test.go @@ -189,7 +189,7 @@ func TestAcquireTokenByAuthCode(t *testing.T) { if err == nil { t.Fatal("unexpected nil error from AcquireTokenSilent") } - tk, err := client.AcquireTokenByAuthCode(context.Background(), "fake_auth_code", tokenScope) + tk, err := client.AcquireTokenByAuthCode(context.Background(), "fake_auth_code", "fake_redirect_uri", tokenScope) if err != nil { t.Fatal(err) } diff --git a/apps/internal/base/base.go b/apps/internal/base/base.go index 5f2f2bcd..f20926c5 100644 --- a/apps/internal/base/base.go +++ b/apps/internal/base/base.go @@ -53,11 +53,12 @@ type AcquireTokenSilentParameters struct { // Code challenges are used to secure authorization code grants; for more information, visit // https://tools.ietf.org/html/rfc7636. type AcquireTokenAuthCodeParameters struct { - Scopes []string - Code string - Challenge string - AppType accesstokens.AppType - Credential *accesstokens.Credential + Scopes []string + Code string + Challenge string + RedirectURI string + AppType accesstokens.AppType + Credential *accesstokens.Credential } // AuthResult contains the results of one token acquisition operation in PublicClientApplication @@ -235,7 +236,7 @@ func (b Client) AcquireTokenSilent(ctx context.Context, silent AcquireTokenSilen func (b Client) AcquireTokenByAuthCode(ctx context.Context, authCodeParams AcquireTokenAuthCodeParameters) (AuthResult, error) { authParams := b.AuthParams // This is a copy, as we dont' have a pointer receiver and .AuthParams is not a pointer. authParams.Scopes = authCodeParams.Scopes - authParams.Redirecturi = "https://login.microsoftonline.com/common/oauth2/nativeclient" + authParams.Redirecturi = authCodeParams.RedirectURI authParams.AuthorizationType = authority.ATAuthCode var cc *accesstokens.Credential diff --git a/apps/public/public.go b/apps/public/public.go index a392d2a0..fd554499 100644 --- a/apps/public/public.go +++ b/apps/public/public.go @@ -219,50 +219,32 @@ func (pca Client) AcquireTokenByDeviceCode(ctx context.Context, scopes []string) // AcquireTokenByAuthCodeOptions contains the optional parameters used to acquire an access token using the authorization code flow. type AcquireTokenByAuthCodeOptions struct { - Code string Challenge string } -func (a AcquireTokenByAuthCodeOptions) validate() error { - if a.Code == "" && a.Challenge == "" { - return nil - } - - switch "" { - case a.Code: - return fmt.Errorf("AcquireTokenByAuthCode: if you set the Challenge, you must set the Code") - case a.Challenge: - return fmt.Errorf("AcquireTokenByAuthCode: if you set the Code, you must set the Challenge") - } - return nil -} - // AcquireTokenByAuthCodeOption changes options inside AcquireTokenByAuthCodeOptions used in .AcquireTokenByAuthCode(). type AcquireTokenByAuthCodeOption func(a *AcquireTokenByAuthCodeOptions) -// CodeChallenge allows you to provide a code for the .AcquireTokenByAuthCode() call. -func CodeChallenge(code, challenge string) AcquireTokenByAuthCodeOption { +// WithChallenge allows you to provide a code for the .AcquireTokenByAuthCode() call. +func WithChallenge(challenge string) AcquireTokenByAuthCodeOption { return func(a *AcquireTokenByAuthCodeOptions) { - a.Code = code a.Challenge = challenge } } // AcquireTokenByAuthCode is a request to acquire a security token from the authority, using an authorization code. -func (pca Client) AcquireTokenByAuthCode(ctx context.Context, scopes []string, options ...AcquireTokenByAuthCodeOption) (AuthResult, error) { +func (pca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redirectURI string, scopes []string, options ...AcquireTokenByAuthCodeOption) (AuthResult, error) { opts := AcquireTokenByAuthCodeOptions{} for _, o := range options { o(&opts) } - if err := opts.validate(); err != nil { - return AuthResult{}, err - } params := base.AcquireTokenAuthCodeParameters{ - Scopes: scopes, - Code: opts.Code, - Challenge: opts.Challenge, - AppType: accesstokens.ATPublic, + Scopes: scopes, + Code: code, + Challenge: opts.Challenge, + AppType: accesstokens.ATPublic, + RedirectURI: redirectURI, } return pca.base.AcquireTokenByAuthCode(ctx, params) From 49cef7495b197bb2839ca8d4f0282b4312a96e72 Mon Sep 17 00:00:00 2001 From: Joel Hendrix Date: Thu, 4 Mar 2021 13:57:02 -0800 Subject: [PATCH 2/2] update doc strings --- apps/confidential/confidential.go | 1 + apps/public/public.go | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/confidential/confidential.go b/apps/confidential/confidential.go index 9cdcf637..acccf765 100644 --- a/apps/confidential/confidential.go +++ b/apps/confidential/confidential.go @@ -311,6 +311,7 @@ func WithChallenge(challenge string) AcquireTokenByAuthCodeOption { } // AcquireTokenByAuthCode is a request to acquire a security token from the authority, using an authorization code. +// The specified redirect URI must be the same URI that was used when the authorization code was requested. func (cca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redirectURI string, scopes []string, options ...AcquireTokenByAuthCodeOption) (AuthResult, error) { opts := AcquireTokenByAuthCodeOptions{} for _, o := range options { diff --git a/apps/public/public.go b/apps/public/public.go index fd554499..18376360 100644 --- a/apps/public/public.go +++ b/apps/public/public.go @@ -233,6 +233,7 @@ func WithChallenge(challenge string) AcquireTokenByAuthCodeOption { } // AcquireTokenByAuthCode is a request to acquire a security token from the authority, using an authorization code. +// The specified redirect URI must be the same URI that was used when the authorization code was requested. func (pca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redirectURI string, scopes []string, options ...AcquireTokenByAuthCodeOption) (AuthResult, error) { opts := AcquireTokenByAuthCodeOptions{} for _, o := range options {