@ -66,14 +66,9 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView ;
import androidx.recyclerview.widget.RecyclerView ;
import com.google.android.material.textfield.TextInputLayout ;
import com.google.android.material.textfield.TextInputLayout ;
import com.microsoft.identity.client.AuthenticationCallback ;
import com.microsoft.identity.client.IAuthenticationResult ;
import com.microsoft.identity.client.IMultipleAccountPublicClientApplication ;
import com.microsoft.identity.client.IPublicClientApplication ;
import com.microsoft.identity.client.PublicClientApplication ;
import com.microsoft.identity.client.exception.MsalException ;
import net.openid.appauth.AppAuthConfiguration ;
import net.openid.appauth.AppAuthConfiguration ;
import net.openid.appauth.AuthState ;
import net.openid.appauth.AuthorizationException ;
import net.openid.appauth.AuthorizationException ;
import net.openid.appauth.AuthorizationRequest ;
import net.openid.appauth.AuthorizationRequest ;
import net.openid.appauth.AuthorizationResponse ;
import net.openid.appauth.AuthorizationResponse ;
@ -81,6 +76,7 @@ import net.openid.appauth.AuthorizationService;
import net.openid.appauth.AuthorizationServiceConfiguration ;
import net.openid.appauth.AuthorizationServiceConfiguration ;
import net.openid.appauth.ClientAuthentication ;
import net.openid.appauth.ClientAuthentication ;
import net.openid.appauth.ClientSecretPost ;
import net.openid.appauth.ClientSecretPost ;
import net.openid.appauth.NoClientAuthentication ;
import net.openid.appauth.ResponseTypeValues ;
import net.openid.appauth.ResponseTypeValues ;
import net.openid.appauth.TokenResponse ;
import net.openid.appauth.TokenResponse ;
import net.openid.appauth.browser.BrowserBlacklist ;
import net.openid.appauth.browser.BrowserBlacklist ;
@ -328,7 +324,6 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
IntentFilter iff = new IntentFilter ( ) ;
IntentFilter iff = new IntentFilter ( ) ;
iff . addAction ( ACTION_QUICK_GMAIL ) ;
iff . addAction ( ACTION_QUICK_GMAIL ) ;
iff . addAction ( ACTION_QUICK_OAUTH ) ;
iff . addAction ( ACTION_QUICK_OAUTH ) ;
iff . addAction ( ACTION_QUICK_OUTLOOK ) ;
iff . addAction ( ACTION_QUICK_SETUP ) ;
iff . addAction ( ACTION_QUICK_SETUP ) ;
iff . addAction ( ACTION_VIEW_ACCOUNTS ) ;
iff . addAction ( ACTION_VIEW_ACCOUNTS ) ;
iff . addAction ( ACTION_VIEW_IDENTITIES ) ;
iff . addAction ( ACTION_VIEW_IDENTITIES ) ;
@ -1160,10 +1155,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
fragmentTransaction . commit ( ) ;
fragmentTransaction . commit ( ) ;
}
}
private void onOAuth ( Intent intent ) {
private AuthorizationService getAuthorizationService ( ) {
String name = intent . getStringExtra ( "name" ) ;
for ( EmailProvider provider : EmailProvider . loadProfiles ( this ) )
if ( provider . name . equals ( name ) & & provider . oauth ! = null ) {
AppAuthConfiguration appAuthConfig = new AppAuthConfiguration . Builder ( )
AppAuthConfiguration appAuthConfig = new AppAuthConfiguration . Builder ( )
. setBrowserMatcher ( new BrowserBlacklist (
. setBrowserMatcher ( new BrowserBlacklist (
new VersionedBrowserMatcher (
new VersionedBrowserMatcher (
@ -1174,94 +1166,112 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
) ) )
) ) )
. build ( ) ;
. build ( ) ;
AuthorizationService authService = new AuthorizationService ( this , appAuthConfig ) ;
return new AuthorizationService ( this , appAuthConfig ) ;
}
private void onOAuth ( Intent intent ) {
try {
String name = intent . getStringExtra ( "name" ) ;
for ( EmailProvider provider : EmailProvider . loadProfiles ( this ) )
if ( provider . name . equals ( name ) & & provider . oauth ! = null ) {
AuthorizationServiceConfiguration serviceConfig = new AuthorizationServiceConfiguration (
Uri . parse ( provider . oauth . authorizationEndpoint ) ,
Uri . parse ( provider . oauth . tokenEndpoint ) ) ;
AuthState authState = new AuthState ( serviceConfig ) ;
SharedPreferences prefs = PreferenceManager . getDefaultSharedPreferences ( this ) ;
prefs . edit ( ) . putString ( "oauth." + provider . name , authState . jsonSerializeString ( ) ) . apply ( ) ;
AuthorizationRequest authRequest =
AuthorizationRequest authRequest =
new AuthorizationRequest . Builder (
new AuthorizationRequest . Builder (
new AuthorizationServiceConfiguration (
serviceConfig ,
Uri . parse ( provider . oauth . authorizationEndpoint ) ,
Uri . parse ( provider . oauth . tokenEndpoint ) ) ,
provider . oauth . clientId ,
provider . oauth . clientId ,
ResponseTypeValues . CODE ,
ResponseTypeValues . CODE ,
Uri . parse ( provider . oauth . redirectUri ) )
Uri . parse ( provider . oauth . redirectUri ) )
. setScopes ( provider . oauth . scopes )
. setScopes ( provider . oauth . scopes )
. setState ( name )
. setState ( provider. name)
. build ( ) ;
. build ( ) ;
Intent authIntent = authService . getAuthorizationRequestIntent ( authRequest ) ;
Intent authIntent = getAuthorizationService ( ) . getAuthorizationRequestIntent ( authRequest ) ;
startActivityForResult ( authIntent , REQUEST_OAUTH ) ;
startActivityForResult ( authIntent , REQUEST_OAUTH ) ;
return ;
return ;
}
}
Log . unexpectedError ( getSupportFragmentManager ( ) ,
throw new IllegalArgumentException ( "Unknown provider=" + name ) ;
new IllegalArgumentException ( "Unknown provider=" + name ) ) ;
} catch ( Throwable ex ) {
Log . unexpectedError ( getSupportFragmentManager ( ) , ex ) ;
}
}
}
private void onHandleOAuth ( Intent data ) {
private void onHandleOAuth ( @NonNull Intent data ) {
try {
AuthorizationResponse auth = AuthorizationResponse . fromIntent ( data ) ;
AuthorizationResponse auth = AuthorizationResponse . fromIntent ( data ) ;
if ( auth = = null ) {
if ( auth = = null )
AuthorizationException ex = AuthorizationException . fromIntent ( data ) ;
throw AuthorizationException . fromIntent ( data ) ;
Log . unexpectedError ( getSupportFragmentManager ( ) , ex ) ;
return ;
}
for ( EmailProvider provider : EmailProvider . loadProfiles ( this ) )
for ( EmailProvider provider : EmailProvider . loadProfiles ( this ) )
if ( provider . name . equals ( auth . state ) ) {
if ( provider . name . equals ( auth . state ) ) {
AuthorizationService authService = new AuthorizationService ( this ) ;
ClientAuthentication clientAuth = new ClientSecretPost ( provider . oauth . clientSecret ) ;
SharedPreferences prefs = PreferenceManager . getDefaultSharedPreferences ( this ) ;
authService . performTokenRequest (
final AuthState authState = AuthState . jsonDeserialize ( prefs . getString ( "oauth." + provider . name , null ) ) ;
authState . update ( auth , null ) ;
prefs . edit ( ) . remove ( "oauth." + provider . name ) . apply ( ) ;
ClientAuthentication clientAuth ;
if ( provider . oauth . clientSecret = = null )
clientAuth = NoClientAuthentication . INSTANCE ;
else
clientAuth = new ClientSecretPost ( provider . oauth . clientSecret ) ;
getAuthorizationService ( ) . performTokenRequest (
auth . createTokenExchangeRequest ( ) ,
auth . createTokenExchangeRequest ( ) ,
clientAuth ,
clientAuth ,
new AuthorizationService . TokenResponseCallback ( ) {
new AuthorizationService . TokenResponseCallback ( ) {
@Override
@Override
public void onTokenRequestCompleted ( TokenResponse access , AuthorizationException ex ) {
public void onTokenRequestCompleted ( TokenResponse access , AuthorizationException error ) {
if ( access = = null ) {
try {
if ( access = = null )
throw error ;
authState . update ( access , null ) ;
Log . i ( "OAuth token provider=" + provider . name ) ;
if ( "Outlook/Office365" . equals ( provider . name ) ) {
authState . performActionWithFreshTokens ( getAuthorizationService ( ) , new AuthState . AuthStateAction ( ) {
@Override
public void execute ( String accessToken , String idToken , AuthorizationException error ) {
try {
if ( error ! = null )
throw error ;
onOutlook ( accessToken , idToken ) ;
} catch ( Throwable ex ) {
Log . unexpectedError ( getSupportFragmentManager ( ) , ex ) ;
Log . unexpectedError ( getSupportFragmentManager ( ) , ex ) ;
return ;
}
}
}
} ) ;
} else
throw new IllegalArgumentException ( "Unknown action provider=" + provider . name ) ;
// access.accessToken
} catch ( Throwable ex ) {
Log . unexpectedError ( getSupportFragmentManager ( ) , ex ) ;
}
}
}
} ) ;
} ) ;
return ;
return ;
}
}
Log . unexpectedError ( getSupportFragmentManager ( ) ,
throw new IllegalArgumentException ( "Unknown state=" + auth . state ) ;
new IllegalArgumentException ( "Unknown state=" + auth . state ) ) ;
} catch ( Throwable ex ) {
Log . unexpectedError ( getSupportFragmentManager ( ) , ex ) ;
}
}
}
private void onOutlook ( Intent intent ) {
private void onOutlook ( String accessToken , String idToken ) {
PublicClientApplication . createMultipleAccountPublicClientApplication (
this ,
R . raw . msal_config ,
new IPublicClientApplication . IMultipleAccountApplicationCreatedListener ( ) {
@Override
public void onCreated ( IMultipleAccountPublicClientApplication msal ) {
Log . i ( "MSAL app created" ) ;
msal . acquireToken (
ActivitySetup . this ,
// "openid", "offline_access", "profile", "email"
// https://docs.microsoft.com/en-us/graph/permissions-reference
new String [ ] {
"openid" , "offline_access" , "profile" , "email" ,
"User.Read" , "Mail.ReadWrite" , "Mail.Send" , "MailboxSettings.ReadWrite" } ,
new AuthenticationCallback ( ) {
@Override
public void onSuccess ( IAuthenticationResult result ) {
Log . i ( "MSAL got token" ) ;
Bundle args = new Bundle ( ) ;
Bundle args = new Bundle ( ) ;
args . putString ( "token" , result . getAccessToken ( ) ) ;
args . putString ( "token" , accessToken ) ;
args . putString ( "id" , result . getAccount ( ) . getId ( ) ) ;
args . putString ( "tenant" , result . getAccount ( ) . getTenantId ( ) ) ;
Log . logBundle ( args ) ;
Map < String , ? > claims = result . getAccount ( ) . getClaims ( ) ;
if ( claims ! = null )
for ( String key : claims . keySet ( ) )
Log . i ( key + "=" + claims . get ( key ) ) ;
new SimpleTask < JSONObject > ( ) {
new SimpleTask < JSONObject > ( ) {
@Override
@Override
@ -1271,7 +1281,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
// https://docs.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http#http-request
// https://docs.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http#http-request
URL url = new URL ( "https://graph.microsoft.com/v1.0/me" +
URL url = new URL ( "https://graph.microsoft.com/v1.0/me" +
"?$select=displayName,otherMails" ) ;
"?$select=displayName,otherMails" ) ;
Log . i ( "MS AL fetching " + url ) ;
Log . i ( "MS Graph fetching " + url ) ;
HttpURLConnection request = ( HttpURLConnection ) url . openConnection ( ) ;
HttpURLConnection request = ( HttpURLConnection ) url . openConnection ( ) ;
request . setReadTimeout ( 15 * 1000 ) ;
request . setReadTimeout ( 15 * 1000 ) ;
@ -1283,7 +1293,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
request . connect ( ) ;
request . connect ( ) ;
try {
try {
Log . i ( "MS AL getting response") ;
Log . i ( "MS Graph getting response") ;
String json = Helper . readStream ( request . getInputStream ( ) , StandardCharsets . UTF_8 . name ( ) ) ;
String json = Helper . readStream ( request . getInputStream ( ) , StandardCharsets . UTF_8 . name ( ) ) ;
return new JSONObject ( json ) ;
return new JSONObject ( json ) ;
} finally {
} finally {
@ -1293,7 +1303,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
@Override
@Override
protected void onExecuted ( Bundle args , JSONObject data ) {
protected void onExecuted ( Bundle args , JSONObject data ) {
Log . i ( "MS AL " + data ) ;
Log . i ( "MS Graph " + data ) ;
try {
try {
JSONArray otherMails = data . getJSONArray ( "otherMails" ) ;
JSONArray otherMails = data . getJSONArray ( "otherMails" ) ;
@ -1408,25 +1418,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
Log . unexpectedError ( getSupportFragmentManager ( ) , ex ) ;
Log . unexpectedError ( getSupportFragmentManager ( ) , ex ) ;
}
}
} . execute ( ActivitySetup . this , args , "graph:profile" ) ;
} . execute ( ActivitySetup . this , args , "graph:profile" ) ;
}
@Override
public void onError ( MsalException ex ) {
Log . e ( ex ) ;
}
@Override
public void onCancel ( ) {
Log . w ( "MSAL cancelled" ) ;
}
} ) ;
}
@Override
public void onError ( MsalException ex ) {
Log . e ( "MSAL" , ex ) ;
}
} ) ;
}
}
private void onViewQuickSetup ( Intent intent ) {
private void onViewQuickSetup ( Intent intent ) {
@ -1580,8 +1572,6 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
onGmail ( intent ) ;
onGmail ( intent ) ;
else if ( ACTION_QUICK_OAUTH . equals ( action ) )
else if ( ACTION_QUICK_OAUTH . equals ( action ) )
onOAuth ( intent ) ;
onOAuth ( intent ) ;
else if ( ACTION_QUICK_OUTLOOK . equals ( action ) )
onOutlook ( intent ) ;
else if ( ACTION_QUICK_SETUP . equals ( action ) )
else if ( ACTION_QUICK_SETUP . equals ( action ) )
onViewQuickSetup ( intent ) ;
onViewQuickSetup ( intent ) ;
else if ( ACTION_VIEW_ACCOUNTS . equals ( action ) )
else if ( ACTION_VIEW_ACCOUNTS . equals ( action ) )