-
Notifications
You must be signed in to change notification settings - Fork 22
[WIP]Updates for MSAL 0.4 #22
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,48 @@ | ||
apply plugin: 'com.android.application' | ||
|
||
android { | ||
compileSdkVersion 27 | ||
buildToolsVersion "28.0.3" | ||
compileSdkVersion 28 | ||
defaultConfig { | ||
applicationId "com.azuresamples.msalandroidapp" | ||
minSdkVersion 21 | ||
targetSdkVersion 27 | ||
targetSdkVersion 28 | ||
versionCode 1 | ||
versionName "1.0" | ||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" | ||
} | ||
buildTypes { | ||
debug{ | ||
|
||
} | ||
release { | ||
minifyEnabled false | ||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||
} | ||
} | ||
flavorDimensions "main" | ||
productFlavors { | ||
local { | ||
applicationIdSuffix ".local" | ||
versionNameSuffix "-local" | ||
resValue("string", "application_name", "msal-local") | ||
} | ||
dist { | ||
applicationIdSuffix ".dist" | ||
versionNameSuffix "-dist" | ||
resValue("string", "application_name", "msal-dist") | ||
} | ||
} | ||
} | ||
|
||
dependencies { | ||
implementation project(':msal') | ||
implementation fileTree(dir: 'libs', include: ['*.jar']) | ||
implementation "com.android.support:appcompat-v7:28.0.0" | ||
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { | ||
exclude group: 'com.android.support', module: 'support-annotations' | ||
}) | ||
implementation 'com.android.volley:volley:1.1.1' | ||
implementation 'com.microsoft.identity.client:msal:0.3.+' | ||
|
||
|
||
testImplementation 'junit:junit:4.12' | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,8 +30,8 @@ | |
|
||
<!--Add in your scheme/host from registered redirect URI--> | ||
<data android:scheme="msauth" | ||
android:host= "YOUR_PACKAGE_NAME - must be registered at https://aka.ms/MobileAppReg" | ||
android:path= "/YOUR_DECODED_SIGNATURE_HASH - must be registered at https://aka.ms/MobileAppReg>" /> | ||
android:host= "com.azuresamples.msalandroidapp" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it was on purpose to keep it in this way.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. I'll put back the original values... prior to actually merging. Leaving it this way for testing. |
||
android:path= "/hk4Z0/bBPPUC8ll5PHC83WbD65k=" /> | ||
</intent-filter> | ||
</activity> | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,44 @@ | ||
package com.azuresamples.msalandroidapp; | ||
|
||
import android.app.Activity; | ||
import android.content.Intent; | ||
import android.support.v7.app.AppCompatActivity; | ||
import android.content.Context; | ||
import android.os.AsyncTask; | ||
import android.os.Bundle; | ||
import android.support.annotation.NonNull; | ||
import android.support.annotation.Nullable; | ||
import android.support.v7.app.AppCompatActivity; | ||
import android.util.Log; | ||
import android.view.View; | ||
import android.widget.Button; | ||
import android.widget.TextView; | ||
import android.widget.Toast; | ||
import com.android.volley.*; | ||
|
||
import com.android.volley.DefaultRetryPolicy; | ||
import com.android.volley.Request; | ||
import com.android.volley.RequestQueue; | ||
import com.android.volley.Response; | ||
import com.android.volley.VolleyError; | ||
import com.android.volley.toolbox.JsonObjectRequest; | ||
import com.android.volley.toolbox.Volley; | ||
import com.microsoft.identity.client.AuthenticationCallback; | ||
import com.microsoft.identity.client.IAccount; | ||
import com.microsoft.identity.client.IAuthenticationResult; | ||
import com.microsoft.identity.client.ISingleAccountPublicClientApplication; | ||
import com.microsoft.identity.client.PublicClientApplication; | ||
import com.microsoft.identity.client.exception.MsalClientException; | ||
import com.microsoft.identity.client.exception.MsalException; | ||
import com.microsoft.identity.client.exception.MsalServiceException; | ||
import com.microsoft.identity.client.exception.MsalUiRequiredException; | ||
|
||
import org.json.JSONObject; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import com.microsoft.identity.client.*; | ||
import com.microsoft.identity.client.exception.*; | ||
|
||
public class MainActivity extends AppCompatActivity { | ||
|
||
/* Azure AD v2 Configs */ | ||
final static String[] SCOPES = {"https://graph.microsoft.com/User.Read"}; | ||
final static String[] SCOPES = {"User.Read"}; | ||
final static String MSGRAPH_URL = "https://graph.microsoft.com/v1.0/me"; | ||
|
||
/* UI & Debugging Variables */ | ||
|
@@ -31,7 +47,7 @@ public class MainActivity extends AppCompatActivity { | |
Button signOutButton; | ||
|
||
/* Azure AD Variables */ | ||
private PublicClientApplication sampleApp; | ||
private ISingleAccountPublicClientApplication sampleApp; | ||
private IAuthenticationResult authResult; | ||
|
||
@Override | ||
|
@@ -54,29 +70,66 @@ public void onClick(View v) { | |
} | ||
}); | ||
|
||
/* Configure your sample app and save state for this activity */ | ||
sampleApp = new PublicClientApplication( | ||
this.getApplicationContext(), | ||
R.raw.auth_config); | ||
new CreateSingleAccountPublicClientApplication().execute(this.getApplicationContext()); | ||
|
||
} | ||
|
||
/* Attempt to get a user and acquireTokenSilent | ||
* If this fails we do an interactive request | ||
*/ | ||
sampleApp.getAccounts(new PublicClientApplication.AccountsLoadedCallback() { | ||
// | ||
|
||
private class CreateSingleAccountPublicClientApplication extends AsyncTask<Context, Void, ISingleAccountPublicClientApplication> { | ||
|
||
@Override | ||
protected ISingleAccountPublicClientApplication doInBackground(Context... contexts) { | ||
|
||
ISingleAccountPublicClientApplication app = null; | ||
try { | ||
app = PublicClientApplication.createSingleAccountPublicClientApplication(contexts[0], R.raw.auth_config); | ||
} catch (InterruptedException e) { | ||
e.printStackTrace(); | ||
} catch (MsalException e) { | ||
e.printStackTrace(); | ||
} | ||
return app; | ||
} | ||
|
||
@Override | ||
protected void onPostExecute(ISingleAccountPublicClientApplication app){ | ||
sampleApp = app; | ||
checkForAccountAndSignInSilently(); | ||
} | ||
|
||
} | ||
|
||
private void checkForAccountAndSignInSilently(){ | ||
|
||
sampleApp.getCurrentAccountAsync(new ISingleAccountPublicClientApplication.CurrentAccountCallback() { | ||
@Override | ||
public void onAccountsLoaded(final List<IAccount> accounts) { | ||
public void onAccountLoaded(@Nullable IAccount activeAccount) { | ||
if(activeAccount != null) { | ||
getSilentToken(); | ||
} | ||
} | ||
|
||
if (!accounts.isEmpty()) { | ||
/* This sample doesn't support multi-account scenarios, use the first account */ | ||
sampleApp.acquireTokenSilentAsync(SCOPES, accounts.get(0), getAuthSilentCallback()); | ||
} else { | ||
/* No accounts or >1 account */ | ||
@Override | ||
public void onAccountChanged(@Nullable IAccount priorAccount, @Nullable IAccount currentAccount) { | ||
if(currentAccount != null) { | ||
getSilentToken(); | ||
} | ||
} | ||
|
||
@Override | ||
public void onError(@NonNull Exception exception) { | ||
|
||
} | ||
}); | ||
} | ||
|
||
private void getSilentToken(){ | ||
|
||
sampleApp.acquireTokenSilentAsync(SCOPES, getDefaultAuthority(), false, getAuthSilentCallback()); | ||
|
||
} | ||
|
||
// | ||
// Core Identity methods used by MSAL | ||
// ================================== | ||
|
@@ -89,44 +142,73 @@ public void onAccountsLoaded(final List<IAccount> accounts) { | |
* Callback will call Graph api w/ access token & update UI | ||
*/ | ||
private void onCallGraphClicked() { | ||
sampleApp.acquireToken(getActivity(), SCOPES, getAuthInteractiveCallback()); | ||
//sampleApp.acquireToken(getActivity(), SCOPES, getAuthInteractiveCallback()); | ||
sampleApp.signIn(getActivity(), SCOPES, new AuthenticationCallback() { | ||
@Override | ||
public void onSuccess(IAuthenticationResult authenticationResult) { | ||
getSilentToken(); | ||
} | ||
|
||
@Override | ||
public void onError(MsalException exception) { | ||
|
||
} | ||
|
||
@Override | ||
public void onCancel() { | ||
|
||
} | ||
}); | ||
} | ||
|
||
/* Clears an account's tokens from the cache. | ||
* Logically similar to "sign out" but only signs out of this app. | ||
* User will get interactive SSO if trying to sign back-in. | ||
*/ | ||
private void onSignOutClicked() { | ||
|
||
|
||
/* Attempt to get a user and acquireTokenSilent | ||
* If this fails we do an interactive request | ||
*/ | ||
sampleApp.getAccounts(new PublicClientApplication.AccountsLoadedCallback() { | ||
sampleApp.getCurrentAccountAsync(new ISingleAccountPublicClientApplication.CurrentAccountCallback() { | ||
@Override | ||
public void onAccountsLoaded(final List<IAccount> accounts) { | ||
|
||
if (accounts.isEmpty()) { | ||
/* No accounts to remove */ | ||
|
||
} else { | ||
for (final IAccount account : accounts) { | ||
sampleApp.removeAccount( | ||
account, | ||
new PublicClientApplication.AccountsRemovedCallback() { | ||
@Override | ||
public void onAccountsRemoved(Boolean isSuccess) { | ||
if (isSuccess) { | ||
/* successfully removed account */ | ||
} else { | ||
/* failed to remove account */ | ||
} | ||
} | ||
}); | ||
} | ||
public void onAccountLoaded(@Nullable IAccount activeAccount) { | ||
if(activeAccount != null){ | ||
signOut(); | ||
} | ||
} | ||
|
||
@Override | ||
public void onAccountChanged(@Nullable IAccount priorAccount, @Nullable IAccount currentAccount) { | ||
if(currentAccount != null){ | ||
signOut(); | ||
} | ||
} | ||
|
||
@Override | ||
public void onError(@NonNull Exception exception) { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should show a |
||
} | ||
}); | ||
|
||
|
||
} | ||
|
||
private void signOut(){ | ||
|
||
sampleApp.signOut(new ISingleAccountPublicClientApplication.SignOutCallback() { | ||
@Override | ||
public void onSignOut() { | ||
updateSignedOutUI(); | ||
} | ||
|
||
@Override | ||
public void onError(@NonNull MsalException exception) { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same feedback here regarding a Toast or dialog |
||
} | ||
}); | ||
|
||
} | ||
|
||
/* Use Volley to make an HTTP request to the /me endpoint from MS Graph using an access token */ | ||
|
@@ -196,7 +278,7 @@ private void updateSuccessUI() { | |
signOutButton.setVisibility(View.VISIBLE); | ||
findViewById(R.id.welcome).setVisibility(View.VISIBLE); | ||
((TextView) findViewById(R.id.welcome)).setText("Welcome, " + | ||
authResult.getAccount().getUsername()); | ||
authResult.getAccount().getClaims().get("preferred_username")); | ||
findViewById(R.id.graphData).setVisibility(View.VISIBLE); | ||
} | ||
|
||
|
@@ -224,6 +306,14 @@ public Activity getActivity() { | |
return this; | ||
} | ||
|
||
private String getDefaultAuthority(){ | ||
if(sampleApp != null){ | ||
return sampleApp.getConfiguration().getDefaultAuthority().getAuthorityURL().toString(); | ||
}else{ | ||
return ""; | ||
} | ||
} | ||
|
||
/* Callback used in for silent acquireToken calls. | ||
* Looks if tokens are in the cache (refreshes if necessary and if we don't forceRefresh) | ||
* else errors that we need to do an interactive request. | ||
|
@@ -278,7 +368,7 @@ private AuthenticationCallback getAuthInteractiveCallback() { | |
public void onSuccess(IAuthenticationResult authenticationResult) { | ||
/* Successfully got a token, call graph now */ | ||
Log.d(TAG, "Successfully authenticated"); | ||
Log.d(TAG, "ID Token: " + authenticationResult.getIdToken()); | ||
Log.d(TAG, "ID Token: " + authenticationResult.getAccount().getClaims().get("id_token")); | ||
|
||
/* Store the auth result */ | ||
authResult = authenticationResult; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the plan around using this value vs loading from Maven central?