Skip to content

Commit

Permalink
Merge pull request #330 from AzureAD/shoatman-command
Browse files Browse the repository at this point in the history
Added command objects to wrap invocation of controllers
  • Loading branch information
shoatman committed Aug 27, 2018
2 parents c8ff3ba + fe1fd4f commit c8cc40f
Show file tree
Hide file tree
Showing 21 changed files with 576 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@ public void testGetUsers() throws MsalException, PackageManager.NameNotFoundExce

/**
* Verify {@link PublicClientApplication#acquireToken(Activity, String[], AuthenticationCallback)}.
* AcquireToken interactive call ask token for scope1 and scope2.
* AcquireTokenSilent call ask token for scope3. No access token will be found. Refresh token returned in the interactive
* acquireToken interactive call ask token for scope1 and scope2.
* acquireTokenSilent call ask token for scope3. No access token will be found. Refresh token returned in the interactive
* request will be used for silent request. Since no intersection between {scope1, scope2} and {scope3}, there will be
* two access token entries in the cache.
*/
Expand Down Expand Up @@ -788,8 +788,8 @@ String getFinalAuthUrl() throws UnsupportedEncodingException {

/**
* Verify {@link PublicClientApplication#acquireToken(Activity, String[], String, UiBehavior, String, String[], String, AuthenticationCallback)}.
* AcquireToken asks token for {scope1, scope2}.
* AcquireTokenSilent asks for {scope2}. Since forcePrompt is set for the silent request, RT request will be sent. There is
* acquireToken asks token for {scope1, scope2}.
* acquireTokenSilent asks for {scope2}. Since forcePrompt is set for the silent request, RT request will be sent. There is
* intersection, old entry will be removed. There will be only one access token left.
*/
@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
/**
* MSAL internal representation for token cache.
*/
class TokenCache {
public class TokenCache {
private static final String TAG = TokenCache.class.getSimpleName();

private static final int DEFAULT_EXPIRATION_BUFFER = 300;
Expand Down Expand Up @@ -95,6 +95,7 @@ class TokenCache {
MicrosoftStsTokenResponse,
MicrosoftAccount,
MicrosoftRefreshToken> initCommonCache(final Context context) {

// Init the new-schema cache
final ICacheKeyValueDelegate cacheKeyValueDelegate = new CacheKeyValueDelegate();
final IStorageHelper storageHelper = new StorageHelper(context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ protected void onCreate(final Bundle savedInstanceState) {

mChromePackageWithCustomTabSupport = MsalUtils.getChromePackageWithCustomTabSupport(getApplicationContext());


// If activity is killed by the os, savedInstance will be the saved bundle.
if (savedInstanceState != null) {
Logger.verbose(TAG, null, "AuthenticationActivity is re-created after killed by the os.");
Expand Down Expand Up @@ -105,6 +106,7 @@ protected void onStart() {
super.onStart();
if (mChromePackageWithCustomTabSupport != null) {
warmUpCustomTabs();

}
}

Expand Down Expand Up @@ -288,4 +290,5 @@ private void sendError(final String errorCode, final String errorDescription) {
errorIntent.putExtra(Constants.UIResponse.ERROR_DESCRIPTION, errorDescription);
returnToCaller(Constants.UIResponse.AUTH_CODE_ERROR, errorIntent);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
* </pre>
*/
public final class BrowserTabActivity extends Activity {
private static final String TAG = BrowserTabActivity.class.getSimpleName();
//private static final String TAG = BrowserTabActivity.class.getSimpleName();

@Override
protected void onCreate(final Bundle savedInstanceState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
import android.content.pm.PackageManager;
import android.support.annotation.NonNull;

import com.microsoft.identity.client.controllers.LocalMSALController;
import com.microsoft.identity.client.controllers.MSALAcquireTokenOperationParameters;
import com.microsoft.identity.client.controllers.MSALInteractiveTokenCommand;
import com.microsoft.identity.common.adal.internal.AuthenticationConstants;
import com.microsoft.identity.common.internal.dto.Account;
import com.microsoft.identity.common.internal.logging.DiagnosticContext;
Expand All @@ -38,8 +41,10 @@
import com.microsoft.identity.msal.BuildConfig;

import java.net.URL;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;
Expand Down Expand Up @@ -443,7 +448,7 @@ public User getUser(final String userIdentifier) throws MsalClientException {
*/
public void handleInteractiveRequestRedirect(int requestCode, int resultCode, final Intent data) {
InteractiveRequest.onActivityResult(requestCode, resultCode, data);
//MSALApiDispatcher.CompleteInteractive(requestCode, resultCode, data);
//com.microsoft.identity.client.MSALApiDispatcher.CompleteInteractive(requestCode, resultCode, data);
}

// Interactive APIs. Will launch the system browser with web UI.
Expand All @@ -470,19 +475,26 @@ public void acquireToken(@NonNull final Activity activity, @NonNull final String
final String telemetryRequestId = Telemetry.generateNewRequestId();
ApiEvent.Builder apiEventBuilder = createApiEventBuilder(telemetryRequestId, API_ID_ACQUIRE);


/*
MSALAcquireTokenRequest request = new MSALAcquireTokenRequest();
MSALAcquireTokenOperationParameters params = new MSALAcquireTokenOperationParameters();
request.setScopes(Arrays.asList(scopes));
request.setClientId(mClientId);
request.setRedirectUri(mRedirectUri);
request.setAppContext(mAppContext);
request.setActivity(activity);
params.setScopes(Arrays.asList(scopes));
params.setClientId(mClientId);
params.setRedirectUri(mRedirectUri);
params.setActivity(activity);
params.setTokenCache(TokenCache.initCommonCache(mAppContext));
MSALApiDispatcher.BeginInteractive(new LocalMSALController(), request);
MSALInteractiveTokenCommand command = new MSALInteractiveTokenCommand();
command.setContext(mAppContext);
command.setCallback(callback);
command.setParameters(params);
command.setController(new LocalMSALController());
com.microsoft.identity.client.MSALApiDispatcher.BeginInteractive(command);
*/


acquireTokenInteractive(activity, scopes, "", UiBehavior.SELECT_ACCOUNT, "", null, "", null, wrapCallbackForTelemetryIntercept(apiEventBuilder, callback), telemetryRequestId, apiEventBuilder);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@
public enum UiBehavior {

/**
* AcquireToken will send prompt=select_account to the authorize endpoint. Shows a list of users from which can be
* acquireToken will send prompt=select_account to the authorize endpoint. Shows a list of users from which can be
* selected for authentication.
*/
SELECT_ACCOUNT,

/**
* AcquireToken will send prompt=login to the authorize endpoint. The user will always be prompted for credentials by the service.
* acquireToken will send prompt=login to the authorize endpoint. The user will always be prompted for credentials by the service.
*/
FORCE_LOGIN,

/**
* AcquireToken will send prompt=consent to the authorize endpoint. The user will be prompted to consent even if consent was granted before.
* acquireToken will send prompt=consent to the authorize endpoint. The user will be prompted to consent even if consent was granted before.
*/
CONSENT
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,45 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.client.controllers;

import android.content.Intent;

import com.microsoft.identity.client.AuthenticationResult;

public class BrokerMSALController extends MSALController {

@Override
public void AcquireToken(MSALAcquireTokenRequest request) {

public AuthenticationResult acquireToken(MSALAcquireTokenOperationParameters request) {
throw new UnsupportedOperationException();
}

@Override
public void CompleteAcquireToken(int requestCode, int resultCode, Intent data) {

public void completeAcquireToken(int requestCode, int resultCode, Intent data) {
throw new UnsupportedOperationException();
}

@Override
public void AcquireTokenSilent(MSALAcquireTokenSilentRequest request) {

public AuthenticationResult acquireTokenSilent(MSALAcquireTokenSilentOperationParameters request) {
throw new UnsupportedOperationException();
}

}
Original file line number Diff line number Diff line change
@@ -1,63 +1,144 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.client.controllers;

import android.content.Intent;

import com.microsoft.identity.client.AuthenticationResult;
import com.microsoft.identity.common.internal.providers.microsoft.microsoftsts.MicrosoftStsAuthorizationRequest;
import com.microsoft.identity.common.internal.providers.microsoft.microsoftsts.MicrosoftStsOAuth2Configuration;
import com.microsoft.identity.common.internal.providers.microsoft.microsoftsts.MicrosoftStsOAuth2Strategy;
import com.microsoft.identity.common.internal.providers.oauth2.AuthorizationConfiguration;
import com.microsoft.identity.common.internal.providers.oauth2.AuthorizationRequest;
import com.microsoft.identity.common.internal.providers.oauth2.AuthorizationResponse;
import com.microsoft.identity.common.internal.providers.oauth2.AuthorizationResult;
import com.microsoft.identity.common.internal.providers.oauth2.AuthorizationStatus;
import com.microsoft.identity.common.internal.providers.oauth2.AuthorizationStrategy;
import com.microsoft.identity.common.internal.providers.oauth2.OAuth2Strategy;
import com.microsoft.identity.common.internal.providers.oauth2.TokenRequest;
import com.microsoft.identity.common.internal.providers.oauth2.TokenResult;
import com.microsoft.identity.common.internal.ui.AuthorizationStrategyFactory;
import com.microsoft.identity.common.internal.ui.browser.BrowserAuthorizationStrategy;
import com.microsoft.identity.common.internal.util.StringUtil;

import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;


public class LocalMSALController extends MSALController{
public class LocalMSALController extends MSALController {

private OAuth2Strategy mOAuthStrategy = null;
private AuthorizationStrategy mAuthorizationStrategy = null;

@Override
public void AcquireToken(MSALAcquireTokenRequest request) throws ExecutionException, InterruptedException {
public AuthenticationResult acquireToken(MSALAcquireTokenOperationParameters parameters) throws ExecutionException, InterruptedException {

//TODO: Use factory to get applicable oAuth and Authorization strategies
mOAuthStrategy = new MicrosoftStsOAuth2Strategy(new MicrosoftStsOAuth2Configuration());

//TODO: Map MSAL Acquire Token Request to Authorization Request
AuthorizationRequest authRequest = new MicrosoftStsAuthorizationRequest();
//1) TODO: Use factory to get applicable oAuth and Authorization strategies
OAuth2Strategy oAuth2Strategy = new MicrosoftStsOAuth2Strategy(new MicrosoftStsOAuth2Configuration());

authRequest.setClientId(request.getClientId());
authRequest.setRedirectUri(request.getRedirectUri());
authRequest.setScope(StringUtil.join(' ', request.getScopes()));
//2) Gather authorization interactively
AuthorizationResult result = performAuthorizationRequest(oAuth2Strategy, parameters);

if (result.getAuthorizationStatus().equals(AuthorizationStatus.SUCCESS)) {
//3) Exchange authorization code for token
TokenResult tokenResult = performTokenRequest(oAuth2Strategy, result.getAuthorizationResponse(), parameters);
if (tokenResult != null && tokenResult.getSuccess()) {
//4) Save tokens in token cache
//saveTokens(oAuth2Strategy, getAuthorizationRequest(oAuth2Strategy, parameters), tokenResult.getTokenResponse(), parameters.getTokenCache());
}
}

//TODO: Replace with factory to create the correct Authorization Strategy based on device capabilities and configuration
mAuthorizationStrategy = AuthorizationStrategyFactory.getInstance().getAuthorizationStrategy(request.getActivity(), AuthorizationConfiguration.getInstance());
throw new UnsupportedOperationException();
}

Future<AuthorizationResult> future = mOAuthStrategy.requestAuthorization(authRequest, mAuthorizationStrategy);
private AuthorizationResult performAuthorizationRequest(OAuth2Strategy strategy, MSALAcquireTokenOperationParameters parameters) throws ExecutionException, InterruptedException {

future.get();
//TODO: Replace with factory to create the correct Authorization Strategy based on device capabilities and configuration
mAuthorizationStrategy = AuthorizationStrategyFactory.getInstance().getAuthorizationStrategy(parameters.getActivity(), AuthorizationConfiguration.getInstance());

Future<AuthorizationResult> future = strategy.requestAuthorization(getAuthorizationRequest(parameters), mAuthorizationStrategy);

//We could implement Timeout Here if we wish instead of looping forever
//We could implement Timeout Here if we wish instead of blocking indefinitely
//future.get(10, TimeUnit.MINUTES); // Need to handle timeout exception in the scenario it doesn't return within a reasonable amount of time
//AuthorizationResult authorizationResult = future.get();
AuthorizationResult result = future.get();

return result;

}

private AuthorizationRequest getAuthorizationRequest(MSALAcquireTokenOperationParameters parameters) {
AuthorizationRequest authRequest = new MicrosoftStsAuthorizationRequest();

String scopes = StringUtil.join(' ', parameters.getScopes());

authRequest.setClientId(parameters.getClientId());
authRequest.setRedirectUri(parameters.getRedirectUri());
authRequest.setScope(scopes);
authRequest.setResponseType(AuthorizationRequest.ResponseTypes.CODE);

return authRequest;
}

private TokenResult performTokenRequest(OAuth2Strategy strategy, AuthorizationResponse response, MSALAcquireTokenOperationParameters parameters) {

TokenRequest tokenRequest = new TokenRequest();

tokenRequest.setCode(response.getCode());
tokenRequest.setClientId(parameters.getClientId());
tokenRequest.setRedirectUri(parameters.getRedirectUri());
tokenRequest.setScope(StringUtil.join(' ', parameters.getScopes()));
tokenRequest.setGrantType(TokenRequest.GrantTypes.AUTHORIZATION_CODE);

TokenResult tokenResult = null;

try {
tokenResult = strategy.requestToken(tokenRequest);
} catch (IOException e) {
//TODO: Figure out exception handling
}

return tokenResult;

}

/*
private void saveTokens(OAuth2Strategy strategy, AuthorizationRequest request, TokenResponse tokenResponse, MsalOAuth2TokenCache tokenCache){
try {
tokencCache.saveTokens(mOAuthStrategy, authRequest, tokenResult.getTokenResponse());
} catch (ClientException e) {
e.printStackTrace();
}
}
*/


@Override
public void CompleteAcquireToken(int requestCode, int resultCode, final Intent data) {
public void completeAcquireToken(int requestCode, int resultCode, final Intent data) {
mAuthorizationStrategy.completeAuthorization(requestCode, resultCode, data);
}

@Override
public void AcquireTokenSilent(MSALAcquireTokenSilentRequest request) {

public AuthenticationResult acquireTokenSilent(MSALAcquireTokenSilentOperationParameters request) {
throw new UnsupportedOperationException();
}
}

0 comments on commit c8cc40f

Please sign in to comment.