Skip to content

Commit

Permalink
Merge pull request #351 from TLFilip/Add_pkce_cusom_headers
Browse files Browse the repository at this point in the history
Add custom headers to social token request [SDK-2080]
  • Loading branch information
lbalmaceda committed Dec 15, 2020
2 parents 062adae + b34bd14 commit 00360e3
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 13 deletions.
16 changes: 11 additions & 5 deletions auth0/src/main/java/com/auth0/android/provider/OAuthManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,15 @@ class OAuthManager extends ResumableManager {
private CustomTabsOptions ctOptions;
private Integer idTokenVerificationLeeway;
private String idTokenVerificationIssuer;
private Map<String, String> headers;

OAuthManager(@NonNull Auth0 account, @NonNull AuthCallback callback, @NonNull Map<String, String> parameters, @NonNull CustomTabsOptions ctOptions) {
this.account = account;
this.callback = callback;
this.parameters = new HashMap<>(parameters);
this.apiClient = new AuthenticationAPIClient(account);
this.ctOptions = ctOptions;
this.headers = new HashMap<>();
}

void useFullScreen(boolean useFullScreen) {
Expand All @@ -101,7 +103,7 @@ void setIdTokenVerificationIssuer(String issuer) {
}

void startAuthentication(Activity activity, String redirectUri, int requestCode) {
addPKCEParameters(parameters, redirectUri);
addPKCEParameters(parameters, redirectUri, headers);
addClientParameters(parameters, redirectUri);
addValidationParameters(parameters);
Uri uri = buildAuthorizeUri();
Expand All @@ -114,6 +116,10 @@ void startAuthentication(Activity activity, String redirectUri, int requestCode)
}
}

void setHeaders(@NonNull Map<String, String> headers) {
this.headers.putAll(headers);
}

@SuppressWarnings("ConstantConditions")
@Override
boolean resume(AuthorizeResult result) {
Expand Down Expand Up @@ -305,12 +311,12 @@ private Uri buildAuthorizeUri() {
return uri;
}

private void addPKCEParameters(Map<String, String> parameters, String redirectUri) {
private void addPKCEParameters(Map<String, String> parameters, String redirectUri, Map<String, String> headers) {
if (!shouldUsePKCE()) {
return;
}
try {
createPKCE(redirectUri);
createPKCE(redirectUri, headers);
String codeChallenge = pkce.getCodeChallenge();
parameters.put(KEY_CODE_CHALLENGE, codeChallenge);
parameters.put(KEY_CODE_CHALLENGE_METHOD, METHOD_SHA_256);
Expand Down Expand Up @@ -340,9 +346,9 @@ private void addClientParameters(Map<String, String> parameters, String redirect
parameters.put(KEY_REDIRECT_URI, redirectUri);
}

private void createPKCE(String redirectUri) {
private void createPKCE(String redirectUri, Map<String, String> headers) {
if (pkce == null) {
pkce = new PKCE(apiClient, redirectUri);
pkce = new PKCE(apiClient, redirectUri, headers);
}
}

Expand Down
23 changes: 18 additions & 5 deletions auth0/src/main/java/com/auth0/android/provider/PKCE.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,13 @@

import com.auth0.android.authentication.AuthenticationAPIClient;
import com.auth0.android.authentication.AuthenticationException;
import com.auth0.android.authentication.request.TokenRequest;
import com.auth0.android.callback.BaseCallback;
import com.auth0.android.result.Credentials;

import java.util.HashMap;
import java.util.Map;

/**
* Performs code exchange according to Proof Key for Code Exchange (PKCE) spec.
*/
Expand All @@ -44,26 +48,30 @@ class PKCE {
private final String codeVerifier;
private final String redirectUri;
private final String codeChallenge;
private final Map<String, String> headers;

/**
* Creates a new instance of this class with the given AuthenticationAPIClient.
* The instance should be disposed after a call to getToken().
*
* @param apiClient to get the OAuth Token.
* @param redirectUri going to be used in the OAuth code request.
* @param headers HTTP headers added to the OAuth token request.
* @throws IllegalStateException when either 'US-ASCII` encoding or 'SHA-256' algorithm is not available.
* @see #isAvailable()
*/
public PKCE(@NonNull AuthenticationAPIClient apiClient, String redirectUri) {
this(apiClient, new AlgorithmHelper(), redirectUri);
public PKCE(@NonNull AuthenticationAPIClient apiClient, String redirectUri, @NonNull Map<String, String> headers) {
this(apiClient, new AlgorithmHelper(), redirectUri, headers);
}

@VisibleForTesting
PKCE(@NonNull AuthenticationAPIClient apiClient, @NonNull AlgorithmHelper algorithmHelper, @NonNull String redirectUri) {
PKCE(@NonNull AuthenticationAPIClient apiClient, @NonNull AlgorithmHelper algorithmHelper,
@NonNull String redirectUri, @NonNull Map<String, String> headers) {
this.apiClient = apiClient;
this.redirectUri = redirectUri;
this.codeVerifier = algorithmHelper.generateCodeVerifier();
this.codeChallenge = algorithmHelper.generateCodeChallenge(codeVerifier);
this.headers = headers;
}

/**
Expand All @@ -83,8 +91,13 @@ public String getCodeChallenge() {
* @param callback to notify the result of this call to.
*/
public void getToken(String authorizationCode, @NonNull final AuthCallback callback) {
apiClient.token(authorizationCode, redirectUri)
.setCodeVerifier(codeVerifier)
TokenRequest tokenRequest = apiClient.token(authorizationCode, redirectUri);

for (Map.Entry<String, String> entry : headers.entrySet()) {
tokenRequest.addHeader(entry.getKey(), entry.getValue());
}

tokenRequest.setCodeVerifier(codeVerifier)
.start(new BaseCallback<Credentials, AuthenticationException>() {
@Override
public void onSuccess(@Nullable Credentials payload) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ public static class Builder {

private final Auth0 account;
private final Map<String, String> values;
private final Map<String, String> headers;
private boolean useBrowser;
private boolean useFullscreen;
private PKCE pkce;
Expand All @@ -174,6 +175,7 @@ public static class Builder {
this.useBrowser = true;
this.useFullscreen = false;
this.ctOptions = CustomTabsOptions.newBuilder().build();
this.headers = new HashMap<>();
withResponseType(ResponseType.CODE);
withScope(SCOPE_TYPE_OPENID);
}
Expand Down Expand Up @@ -323,6 +325,17 @@ public Builder withScope(@NonNull String scope) {
return this;
}

/**
* Add custom headers for PKCE token request.
*
* @param headers for token request.
* @return the current builder instance
*/
public Builder withHeaders(@NonNull Map<String, String> headers) {
this.headers.putAll(headers);
return this;
}

/**
* Give a connection scope for this request.
*
Expand Down Expand Up @@ -448,6 +461,7 @@ public void start(@NonNull Activity activity, @NonNull AuthCallback callback, in
OAuthManager manager = new OAuthManager(account, callback, values, ctOptions);
manager.useFullScreen(useFullscreen);
manager.useBrowser(useBrowser);
manager.setHeaders(headers);
manager.setPKCE(pkce);
manager.setIdTokenVerificationLeeway(leeway);
manager.setIdTokenVerificationIssuer(issuer);
Expand Down
26 changes: 23 additions & 3 deletions auth0/src/test/java/com/auth0/android/provider/PKCETest.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
Expand Down Expand Up @@ -77,18 +79,18 @@ public class PKCETest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
pkce = new PKCE(apiClient, new AlgorithmHelperMock(CODE_VERIFIER), REDIRECT_URI);
pkce = new PKCE(apiClient, new AlgorithmHelperMock(CODE_VERIFIER), REDIRECT_URI, new HashMap<String, String>());
}

@Test
public void shouldGenerateChallengeFromRandomVerifier() {
PKCE pkce = new PKCE(apiClient, REDIRECT_URI);
PKCE pkce = new PKCE(apiClient, REDIRECT_URI, new HashMap<String, String>());
assertThat(pkce.getCodeChallenge(), is(notNullValue()));
}

@Test
public void shouldGenerateValidRandomCodeChallenge() {
PKCE randomPKCE = new PKCE(apiClient, REDIRECT_URI);
PKCE randomPKCE = new PKCE(apiClient, REDIRECT_URI, new HashMap<String, String>());
String challenge = randomPKCE.getCodeChallenge();
assertThat(challenge, is(notNullValue()));
assertThat(challenge, CoreMatchers.not(Matchers.isEmptyString()));
Expand Down Expand Up @@ -118,6 +120,24 @@ public void shouldGetToken() {
verify(callback).onSuccess(credentials);
}

@Test
public void shouldAddHeaders() {
String header1Name = "header1";
String header1Value = "val1";
String header2Name = "header2";
String header2Value = "val2";
Map<String, String> headers = new HashMap<>();
headers.put(header1Name, header1Value);
headers.put(header2Name, header2Value);
PKCE pkce = new PKCE(apiClient, new AlgorithmHelperMock(CODE_VERIFIER), REDIRECT_URI, headers);
TokenRequest tokenRequest = mock(TokenRequest.class);
when(apiClient.token(AUTHORIZATION_CODE, REDIRECT_URI)).thenReturn(tokenRequest);
when(tokenRequest.setCodeVerifier(CODE_VERIFIER)).thenReturn(tokenRequest);
pkce.getToken(AUTHORIZATION_CODE, callback);
verify(tokenRequest).addHeader(header1Name, header1Value);
verify(tokenRequest).addHeader(header2Name, header2Value);
}

@Test
public void shouldFailToGetToken() {
TokenRequest tokenRequest = mock(TokenRequest.class);
Expand Down

0 comments on commit 00360e3

Please sign in to comment.