-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(react-native-test-app-msal): add support for Android (#894)
- Loading branch information
Showing
33 changed files
with
1,107 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@rnx-kit/react-native-test-app-msal": minor | ||
--- | ||
|
||
Added support for Android |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 162 additions & 0 deletions
162
packages/react-native-test-app-msal/android/build.gradle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import groovy.json.JsonOutput | ||
import groovy.json.JsonSlurper | ||
|
||
import java.nio.file.Paths | ||
|
||
buildscript { | ||
ext.ensureProperty = { config, property -> | ||
if (!config.containsKey(property)) { | ||
throw new MissingPropertyException("Missing '$property' in 'react-native-test-app-msal' config") | ||
} | ||
return config[property] | ||
} | ||
|
||
ext.findFile = { fileName -> | ||
def currentDirPath = rootDir == null ? null : rootDir.toString() | ||
|
||
while (currentDirPath != null) { | ||
def currentDir = file(currentDirPath); | ||
def requestedFile = Paths.get(currentDirPath, fileName).toFile() | ||
|
||
if (requestedFile.exists()) { | ||
return requestedFile | ||
} | ||
|
||
currentDirPath = currentDir.getParent() | ||
} | ||
|
||
return null | ||
} | ||
|
||
ext.findNodeModulesPath = { packageName -> | ||
return findFile(Paths.get('node_modules', packageName).toString()) | ||
} | ||
|
||
ext.getExtProp = { prop, defaultValue -> | ||
return rootProject.ext.has(prop) ? rootProject.ext.get(prop) : defaultValue | ||
} | ||
|
||
ext.getStringArray = { config, property -> | ||
return (!config.containsKey(property) || config[property].size() == 0) | ||
? "" | ||
: "\"${config[property].join('", "')}\"" | ||
} | ||
|
||
ext.kotlinVersion = getExtProp('kotlinVersion', '1.5.31') | ||
|
||
repositories { | ||
google() | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
classpath "com.android.tools.build:gradle:${getExtProp('androidPluginVersion', '4.2.2')}" | ||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" | ||
} | ||
} | ||
|
||
plugins { | ||
id "com.android.library" | ||
id "kotlin-android" | ||
} | ||
|
||
repositories { | ||
maven { | ||
url("${findNodeModulesPath('react-native')}/android") | ||
} | ||
|
||
google() | ||
mavenCentral() | ||
|
||
// https://github.com/AzureAD/microsoft-authentication-library-for-android#step-1-declare-dependency-on-msal | ||
maven { | ||
url 'https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed/maven/v1' | ||
} | ||
} | ||
|
||
android { | ||
def manifest = new JsonSlurper().parseText(findFile('app.json').text) | ||
def config = manifest["react-native-test-app-msal"] | ||
if (config == null) { | ||
throw new MissingPropertyException("Missing 'react-native-test-app-msal' field in 'app.json'") | ||
} | ||
|
||
def signatureHash = ensureProperty(config, "signatureHash") | ||
|
||
compileSdkVersion getExtProp('compileSdkVersion', 31) | ||
defaultConfig { | ||
minSdkVersion getExtProp('minSdkVersion', 23) | ||
targetSdkVersion getExtProp('targetSdkVersion', 29) | ||
|
||
buildConfigField "String[]", | ||
"ReactTestAppMSAL_msaScopes", | ||
"new String[]{${getStringArray(config, "msaScopes")}}" | ||
buildConfigField "String[]", | ||
"ReactTestAppMSAL_orgScopes", | ||
"new String[]{${getStringArray(config, "orgScopes")}}" | ||
|
||
manifestPlaceholders = [ | ||
msalRedirectUriPath: "/$signatureHash" | ||
] | ||
} | ||
sourceSets { | ||
def clientId = ensureProperty(config, "clientId") | ||
|
||
def appProject = rootProject.subprojects.find { it.name == "app" } | ||
def applicationId = appProject.android.defaultConfig.applicationId | ||
def redirectUri = "msauth://$applicationId/${URLEncoder.encode(signatureHash, "UTF-8")}" | ||
|
||
def generatedResDir = file("$buildDir/generated/react-native-test-app-msal/src/main/res/") | ||
generatedResDir.mkdirs() | ||
|
||
task copyMsalConfig(type: Copy) { | ||
def generatedRawDir = file("$generatedResDir/raw") | ||
generatedRawDir.mkdirs() | ||
|
||
def msalConfig = file("$temporaryDir/msal_config.json") | ||
msalConfig.withWriter { | ||
it << JsonOutput.toJson([ | ||
authorities: [ | ||
[ | ||
type: "AAD", | ||
audience: [ | ||
type: "AzureADandPersonalMicrosoftAccount" | ||
], | ||
default: true | ||
], | ||
[ | ||
type: "AAD", | ||
audience: [ | ||
type: "PersonalMicrosoftAccount" | ||
], | ||
], | ||
], | ||
client_id: clientId, | ||
redirect_uri: redirectUri, | ||
broker_redirect_uri_registered: false, | ||
account_mode: "MULTIPLE" | ||
]) | ||
} | ||
|
||
from msalConfig | ||
into generatedRawDir | ||
} | ||
|
||
preBuild.dependsOn(copyMsalConfig) | ||
|
||
main.res.srcDirs += generatedResDir | ||
} | ||
} | ||
|
||
dependencies { | ||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" | ||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" | ||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" | ||
|
||
implementation 'androidx.activity:activity-ktx:1.4.0' | ||
implementation 'com.google.android.material:material:1.4.0' | ||
implementation 'com.microsoft.identity.client:msal:2.2.1' | ||
|
||
//noinspection GradleDynamicVersion | ||
implementation 'com.facebook.react:react-native:+' | ||
} |
3 changes: 3 additions & 0 deletions
3
packages/react-native-test-app-msal/android/gradle.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# These properties are required to enable AndroidX for the test app. | ||
android.useAndroidX=true | ||
android.enableJetifier=true |
24 changes: 24 additions & 0 deletions
24
packages/react-native-test-app-msal/android/src/main/AndroidManifest.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
package="com.microsoft.reacttestapp.msal"> | ||
|
||
<application> | ||
<activity android:name=".MicrosoftAccountsActivity" /> | ||
<activity | ||
android:name="com.microsoft.identity.client.BrowserTabActivity" | ||
android:exported="true"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.VIEW" /> | ||
|
||
<category android:name="android.intent.category.DEFAULT" /> | ||
<category android:name="android.intent.category.BROWSABLE" /> | ||
|
||
<data | ||
android:host="${applicationId}" | ||
android:path="${msalRedirectUriPath}" | ||
android:scheme="msauth" /> | ||
</intent-filter> | ||
</activity> | ||
</application> | ||
|
||
</manifest> |
18 changes: 18 additions & 0 deletions
18
...act-native-test-app-msal/android/src/main/java/com/microsoft/reacttestapp/msal/Account.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.microsoft.reacttestapp.msal | ||
|
||
import com.microsoft.identity.client.IAccount | ||
|
||
data class Account( | ||
val userPrincipalName: String, | ||
val accountType: AccountType | ||
) { | ||
override fun toString(): String { | ||
return "$userPrincipalName (${accountType.description()})" | ||
} | ||
} | ||
|
||
fun List<IAccount>.find(userPrincipalName: String, accountType: AccountType): IAccount? { | ||
return find { | ||
it.username == userPrincipalName && it.accountType() == accountType | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
...native-test-app-msal/android/src/main/java/com/microsoft/reacttestapp/msal/AccountType.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.microsoft.reacttestapp.msal | ||
|
||
import com.microsoft.identity.client.IAccount | ||
|
||
enum class AccountType(val type: String) { | ||
MICROSOFT_ACCOUNT("MicrosoftAccount"), | ||
ORGANIZATIONAL("Organizational"); | ||
|
||
companion object { | ||
// Source: https://docs.microsoft.com/en-us/azure/active-directory/develop/id-tokens | ||
private const val MSA_TENANT = "9188040d-6c67-4c5b-b112-36a304b66dad" | ||
|
||
fun fromIssuer(issuer: String): AccountType { | ||
return if (issuer.contains(MSA_TENANT)) | ||
MICROSOFT_ACCOUNT | ||
else | ||
ORGANIZATIONAL | ||
} | ||
} | ||
|
||
fun description(): String { | ||
return when (this) { | ||
MICROSOFT_ACCOUNT -> "personal" | ||
ORGANIZATIONAL -> "work" | ||
} | ||
} | ||
} | ||
|
||
fun IAccount.accountType(): AccountType { | ||
return AccountType.fromIssuer(claims?.get("iss").toString()) | ||
} |
31 changes: 31 additions & 0 deletions
31
...ve-test-app-msal/android/src/main/java/com/microsoft/reacttestapp/msal/AccountsAdapter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.microsoft.reacttestapp.msal | ||
|
||
import android.content.Context | ||
import android.view.LayoutInflater | ||
import android.view.View | ||
import android.view.ViewGroup | ||
import android.widget.ArrayAdapter | ||
import android.widget.TextView | ||
|
||
class AccountsAdapter( | ||
context: Context, | ||
private val accounts: MutableList<Account> | ||
) : ArrayAdapter<Account>(context, R.layout.account_item, accounts) { | ||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { | ||
val layoutInflater = LayoutInflater.from(parent.context) | ||
val view = convertView ?: layoutInflater.inflate(R.layout.account_item, parent, false) | ||
|
||
val (userPrincipalName, accountType) = accounts[position] | ||
view.findViewById<TextView>(R.id.username).text = userPrincipalName | ||
|
||
val accountTypeText = parent.context.resources.getString(R.string.account_type) | ||
view.findViewById<TextView>(R.id.account_type).text = | ||
String.format(accountTypeText, accountType.description()) | ||
|
||
return view | ||
} | ||
|
||
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View { | ||
return getView(position, convertView, parent) | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
...-test-app-msal/android/src/main/java/com/microsoft/reacttestapp/msal/AccountsViewModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.microsoft.reacttestapp.msal | ||
|
||
import androidx.lifecycle.MutableLiveData | ||
import androidx.lifecycle.ViewModel | ||
|
||
class AccountsViewModel : ViewModel() { | ||
val accounts: MutableLiveData<List<Account>> by lazy { | ||
MutableLiveData<List<Account>>() | ||
} | ||
|
||
val canAddAccount: MutableLiveData<Boolean> by lazy { | ||
MutableLiveData<Boolean>(true) | ||
} | ||
|
||
val canSignOut: MutableLiveData<Boolean> by lazy { | ||
MutableLiveData<Boolean>(false) | ||
} | ||
|
||
val selectedAccount: MutableLiveData<Account> by lazy { | ||
MutableLiveData<Account>() | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
...t-native-test-app-msal/android/src/main/java/com/microsoft/reacttestapp/msal/AuthError.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.microsoft.reacttestapp.msal | ||
|
||
import com.microsoft.identity.common.exception.BaseException | ||
|
||
data class AuthError( | ||
val type: AuthErrorType, | ||
val correlationId: String, | ||
val message: String? | ||
) { | ||
constructor(exception: BaseException) : this( | ||
AuthErrorType.fromMsalException(exception), | ||
exception.correlationId ?: TokenBroker.EMPTY_GUID, | ||
exception.message | ||
) | ||
} |
Oops, something went wrong.