react-native-msal2 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +12 -36
- package/android/src/main/java/com/reactnativemsal/RNMSALModule.kt +511 -0
- package/android/src/main/java/com/reactnativemsal/RNMSALPackage.kt +28 -0
- package/android/src/main/java/com/reactnativemsal/ReadableMapUtils.kt +82 -0
- package/package.json +1 -1
- package/android/src/main/java/com/reactnativemsal/FileUtils.java +0 -80
- package/android/src/main/java/com/reactnativemsal/RNMSALModule.java +0 -482
- package/android/src/main/java/com/reactnativemsal/RNMSALPackage.java +0 -25
- package/android/src/main/java/com/reactnativemsal/ReadableMapUtils.java +0 -105
package/package.json
CHANGED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
package com.reactnativemsal;
|
|
2
|
-
|
|
3
|
-
import java.io.File;
|
|
4
|
-
import java.io.FileOutputStream;
|
|
5
|
-
import java.io.IOException;
|
|
6
|
-
import java.io.InputStream;
|
|
7
|
-
import java.io.OutputStream;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Code copied from org.apache.commons.io/FileUtils.java and org.apache.commons.io/IOUtils.java,
|
|
11
|
-
* v2.8
|
|
12
|
-
*/
|
|
13
|
-
public class FileUtils {
|
|
14
|
-
public static final int DEFAULT_BUFFER_SIZE = 8192;
|
|
15
|
-
public static final int EOF = -1;
|
|
16
|
-
|
|
17
|
-
public static void copyInputStreamToFile(InputStream source, File destination)
|
|
18
|
-
throws IOException {
|
|
19
|
-
try (InputStream inputStream = source) {
|
|
20
|
-
copyToFile(inputStream, destination);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public static void copyToFile(InputStream inputStream, File file) throws IOException {
|
|
25
|
-
try (OutputStream out = openOutputStream(file, false)) {
|
|
26
|
-
copy(inputStream, out);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public static FileOutputStream openOutputStream(File file, boolean append) throws IOException {
|
|
31
|
-
if (file == null) {
|
|
32
|
-
throw new IOException("File cannot be null.");
|
|
33
|
-
}
|
|
34
|
-
if (file.exists()) {
|
|
35
|
-
if (!file.isFile()) {
|
|
36
|
-
throw new IOException("Not a file: " + file);
|
|
37
|
-
}
|
|
38
|
-
if (!file.canWrite()) {
|
|
39
|
-
throw new IOException("File is not writable: '" + file + "'");
|
|
40
|
-
}
|
|
41
|
-
} else {
|
|
42
|
-
File parent = file.getParentFile();
|
|
43
|
-
if (parent != null) {
|
|
44
|
-
if (!parent.mkdirs() && !parent.isDirectory()) {
|
|
45
|
-
throw new IOException("Cannot create directory '" + parent + "'.");
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return new FileOutputStream(file, append);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
public static int copy(InputStream inputStream, OutputStream outputStream) throws IOException {
|
|
53
|
-
long count = copyLarge(inputStream, outputStream);
|
|
54
|
-
if (count > Integer.MAX_VALUE) {
|
|
55
|
-
return EOF;
|
|
56
|
-
}
|
|
57
|
-
return (int) count;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
public static long copyLarge(InputStream inputStream, OutputStream outputStream)
|
|
61
|
-
throws IOException {
|
|
62
|
-
return copy(inputStream, outputStream, DEFAULT_BUFFER_SIZE);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
public static long copy(InputStream inputStream, OutputStream outputStream, int bufferSize)
|
|
66
|
-
throws IOException {
|
|
67
|
-
return copyLarge(inputStream, outputStream, new byte[bufferSize]);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
public static long copyLarge(InputStream inputStream, OutputStream outputStream, byte[] buffer)
|
|
71
|
-
throws IOException {
|
|
72
|
-
long count = 0;
|
|
73
|
-
int n;
|
|
74
|
-
while (EOF != (n = inputStream.read(buffer))) {
|
|
75
|
-
outputStream.write(buffer, 0, n);
|
|
76
|
-
count += n;
|
|
77
|
-
}
|
|
78
|
-
return count;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
@@ -1,482 +0,0 @@
|
|
|
1
|
-
package com.reactnativemsal;
|
|
2
|
-
|
|
3
|
-
import android.content.pm.PackageInfo;
|
|
4
|
-
import android.content.pm.PackageManager;
|
|
5
|
-
import android.content.pm.Signature;
|
|
6
|
-
import android.net.Uri;
|
|
7
|
-
import android.util.Base64;
|
|
8
|
-
import android.util.Log;
|
|
9
|
-
import android.util.Pair;
|
|
10
|
-
|
|
11
|
-
import androidx.annotation.NonNull;
|
|
12
|
-
import androidx.annotation.Nullable;
|
|
13
|
-
|
|
14
|
-
import com.facebook.react.bridge.Arguments;
|
|
15
|
-
import com.facebook.react.bridge.Promise;
|
|
16
|
-
import com.facebook.react.bridge.ReactApplicationContext;
|
|
17
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
18
|
-
import com.facebook.react.bridge.ReactMethod;
|
|
19
|
-
import com.facebook.react.bridge.ReadableArray;
|
|
20
|
-
import com.facebook.react.bridge.ReadableMap;
|
|
21
|
-
import com.facebook.react.bridge.WritableArray;
|
|
22
|
-
import com.facebook.react.bridge.WritableMap;
|
|
23
|
-
import com.microsoft.identity.client.AcquireTokenParameters;
|
|
24
|
-
import com.microsoft.identity.client.AcquireTokenSilentParameters;
|
|
25
|
-
import com.microsoft.identity.client.AuthenticationCallback;
|
|
26
|
-
import com.microsoft.identity.client.IAccount;
|
|
27
|
-
import com.microsoft.identity.client.IAuthenticationResult;
|
|
28
|
-
import com.microsoft.identity.client.IMultiTenantAccount;
|
|
29
|
-
import com.microsoft.identity.client.IMultipleAccountPublicClientApplication;
|
|
30
|
-
import com.microsoft.identity.client.Prompt;
|
|
31
|
-
import com.microsoft.identity.client.PublicClientApplication;
|
|
32
|
-
import com.microsoft.identity.client.SilentAuthenticationCallback;
|
|
33
|
-
import com.microsoft.identity.client.exception.MsalException;
|
|
34
|
-
|
|
35
|
-
import org.json.JSONArray;
|
|
36
|
-
import org.json.JSONException;
|
|
37
|
-
import org.json.JSONObject;
|
|
38
|
-
|
|
39
|
-
import java.io.File;
|
|
40
|
-
import java.io.FileWriter;
|
|
41
|
-
import java.security.MessageDigest;
|
|
42
|
-
import java.util.AbstractMap;
|
|
43
|
-
import java.util.ArrayList;
|
|
44
|
-
import java.util.List;
|
|
45
|
-
import java.util.Map;
|
|
46
|
-
import java.util.regex.Matcher;
|
|
47
|
-
import java.util.regex.Pattern;
|
|
48
|
-
|
|
49
|
-
import static com.reactnativemsal.ReadableMapUtils.getStringOrDefault;
|
|
50
|
-
import static com.reactnativemsal.ReadableMapUtils.getStringOrThrow;
|
|
51
|
-
|
|
52
|
-
public class RNMSALModule extends ReactContextBaseJavaModule {
|
|
53
|
-
private static final String AUTHORITY_TYPE_B2C = "B2C";
|
|
54
|
-
private static final String AUTHORITY_TYPE_AAD = "AAD";
|
|
55
|
-
|
|
56
|
-
private static final Pattern aadAuthorityPattern = Pattern.compile("https://login\\.microsoftonline\\.com/([^/]+)");
|
|
57
|
-
private static final Pattern b2cAuthorityPattern = Pattern.compile("https://([^/]+)/([^/]+)/.+");
|
|
58
|
-
|
|
59
|
-
private IMultipleAccountPublicClientApplication publicClientApplication;
|
|
60
|
-
|
|
61
|
-
public RNMSALModule(ReactApplicationContext reactContext) {
|
|
62
|
-
super(reactContext);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
@NonNull
|
|
66
|
-
@Override
|
|
67
|
-
public String getName() {
|
|
68
|
-
return "RNMSAL";
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@ReactMethod
|
|
72
|
-
public void createPublicClientApplication(ReadableMap params, Promise promise) {
|
|
73
|
-
ReactApplicationContext context = getReactApplicationContext();
|
|
74
|
-
try {
|
|
75
|
-
// We have to make a json file containing the MSAL configuration, then use that file to
|
|
76
|
-
// create the PublicClientApplication
|
|
77
|
-
// We first need to create the JSON model using the passed in parameters
|
|
78
|
-
|
|
79
|
-
JSONObject msalConfigJsonObj = params.hasKey("androidConfigOptions")
|
|
80
|
-
? ReadableMapUtils.toJsonObject(params.getMap("androidConfigOptions"))
|
|
81
|
-
: new JSONObject();
|
|
82
|
-
|
|
83
|
-
// Account mode. Required to be MULTIPLE for this library
|
|
84
|
-
msalConfigJsonObj.put("account_mode", "MULTIPLE");
|
|
85
|
-
|
|
86
|
-
// If broker_redirect_uri_registered is not provided in androidConfigOptions,
|
|
87
|
-
// default it to false
|
|
88
|
-
if (!msalConfigJsonObj.has("broker_redirect_uri_registered")) {
|
|
89
|
-
msalConfigJsonObj.put("broker_redirect_uri_registered", false);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
ReadableMap auth = params.getMap("auth");
|
|
93
|
-
|
|
94
|
-
// Authority
|
|
95
|
-
String authority = getStringOrDefault(auth, "authority", "https://login.microsoftonline.com/common");
|
|
96
|
-
msalConfigJsonObj.put("authority", authority);
|
|
97
|
-
|
|
98
|
-
// Client id
|
|
99
|
-
msalConfigJsonObj.put("client_id", getStringOrThrow(auth, "clientId"));
|
|
100
|
-
|
|
101
|
-
// Redirect URI
|
|
102
|
-
msalConfigJsonObj.put("redirect_uri", auth.hasKey("redirectUri") ? auth.getString("redirectUri") : makeRedirectUri(context).toString());
|
|
103
|
-
|
|
104
|
-
// Authorities
|
|
105
|
-
ReadableArray knownAuthorities = auth.getArray("knownAuthorities");
|
|
106
|
-
// List WILL be instantiated and empty if `knownAuthorities` is null
|
|
107
|
-
List<String> authoritiesList = readableArrayToStringList(knownAuthorities);
|
|
108
|
-
// Make sure the `authority` makes it in the authority list
|
|
109
|
-
if (!authoritiesList.contains(authority)) {
|
|
110
|
-
authoritiesList.add(authority);
|
|
111
|
-
}
|
|
112
|
-
// The authoritiesList is just a list of urls (strings), but the native android MSAL
|
|
113
|
-
// library expects an array of objects, so we have to parse the urls
|
|
114
|
-
JSONArray authoritiesJsonArr = makeAuthoritiesJsonArray(authoritiesList, authority);
|
|
115
|
-
msalConfigJsonObj.put("authorities", authoritiesJsonArr);
|
|
116
|
-
|
|
117
|
-
// Serialize the JSON config to a string
|
|
118
|
-
String serializedMsalConfig = msalConfigJsonObj.toString();
|
|
119
|
-
Log.d("RNMSALModule", serializedMsalConfig);
|
|
120
|
-
|
|
121
|
-
// Create a temporary file and write the serialized config to it
|
|
122
|
-
File file = File.createTempFile("RNMSAL_msal_config", ".tmp");
|
|
123
|
-
file.deleteOnExit();
|
|
124
|
-
FileWriter writer = new FileWriter(file);
|
|
125
|
-
writer.write(serializedMsalConfig);
|
|
126
|
-
writer.close();
|
|
127
|
-
|
|
128
|
-
// Finally, create the PCA with the temporary config file we created
|
|
129
|
-
publicClientApplication =
|
|
130
|
-
PublicClientApplication.createMultipleAccountPublicClientApplication(
|
|
131
|
-
context, file);
|
|
132
|
-
promise.resolve(null);
|
|
133
|
-
} catch (Exception e) {
|
|
134
|
-
promise.reject(e);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
private JSONArray makeAuthoritiesJsonArray(List<String> authorityUrls, String authority) throws JSONException, IllegalArgumentException {
|
|
139
|
-
JSONArray authoritiesJsonArr = new JSONArray();
|
|
140
|
-
boolean foundDefaultAuthority = false;
|
|
141
|
-
|
|
142
|
-
for (String authorityUrl : authorityUrls) {
|
|
143
|
-
JSONObject authorityJsonObj = new JSONObject();
|
|
144
|
-
|
|
145
|
-
// Authority is set as the default if one is not set yet, and it matches `authority`
|
|
146
|
-
if (!foundDefaultAuthority && authorityUrl.equals(authority)) {
|
|
147
|
-
authorityJsonObj.put("default", true);
|
|
148
|
-
foundDefaultAuthority = true;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
Matcher aadAuthorityMatcher = aadAuthorityPattern.matcher(authorityUrl);
|
|
152
|
-
Matcher b2cAuthorityMatcher = b2cAuthorityPattern.matcher(authorityUrl);
|
|
153
|
-
|
|
154
|
-
if (aadAuthorityMatcher.find()) {
|
|
155
|
-
String group = aadAuthorityMatcher.group(1);
|
|
156
|
-
if (group == null)
|
|
157
|
-
throw new IllegalArgumentException("Could not match group 1 for regex https://login.microsoftonline.com/([^/]+) in authority \"" + authorityUrl + "\"");
|
|
158
|
-
|
|
159
|
-
JSONObject audience;
|
|
160
|
-
switch (group) {
|
|
161
|
-
case "common":
|
|
162
|
-
audience = new JSONObject().put("type", "AzureADandPersonalMicrosoftAccount");
|
|
163
|
-
break;
|
|
164
|
-
case "organizations":
|
|
165
|
-
audience = new JSONObject().put("type", "AzureADMultipleOrgs");
|
|
166
|
-
break;
|
|
167
|
-
case "consumers":
|
|
168
|
-
audience = new JSONObject().put("type", "PersonalMicrosoftAccount");
|
|
169
|
-
break;
|
|
170
|
-
default:
|
|
171
|
-
// assume `group` is a tenant id
|
|
172
|
-
audience = new JSONObject().put("type", "AzureADMyOrg").put("tenant_id", group);
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
authorityJsonObj.put("type", AUTHORITY_TYPE_AAD);
|
|
176
|
-
authorityJsonObj.put("audience", audience);
|
|
177
|
-
} else if (b2cAuthorityMatcher.find()) {
|
|
178
|
-
authorityJsonObj.put("type", AUTHORITY_TYPE_B2C);
|
|
179
|
-
authorityJsonObj.put("authority_url", authorityUrl);
|
|
180
|
-
} else {
|
|
181
|
-
throw new IllegalArgumentException("Authority \"" + authorityUrl + "\" doesn't match AAD regex https://login.microsoftonline.com/([^/]+) or B2C regex https://([^/]+)/tfp/([^/]+)/.+");
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
authoritiesJsonArr.put(authorityJsonObj);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// If a default authority was not found, we set the first authority as the default
|
|
188
|
-
if (!foundDefaultAuthority && authoritiesJsonArr.length() > 0) {
|
|
189
|
-
authoritiesJsonArr.getJSONObject(0).put("default", true);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return authoritiesJsonArr;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
private Uri makeRedirectUri(ReactApplicationContext context) throws Exception {
|
|
196
|
-
try {
|
|
197
|
-
final String packageName = context.getPackageName();
|
|
198
|
-
final PackageInfo info = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
|
|
199
|
-
if (info.signatures.length != 1) {
|
|
200
|
-
throw new RuntimeException("RNMSAL expected there to be exactly one signature for package " + packageName);
|
|
201
|
-
}
|
|
202
|
-
Signature signature = info.signatures[0];
|
|
203
|
-
final MessageDigest messageDigest = MessageDigest.getInstance("SHA");
|
|
204
|
-
messageDigest.update(signature.toByteArray());
|
|
205
|
-
final String signatureHash = Base64.encodeToString(messageDigest.digest(), Base64.NO_WRAP);
|
|
206
|
-
Log.d("RNMSALModule", signatureHash);
|
|
207
|
-
|
|
208
|
-
return new Uri.Builder().scheme("msauth")
|
|
209
|
-
.authority(packageName)
|
|
210
|
-
.appendPath(signatureHash)
|
|
211
|
-
.build();
|
|
212
|
-
} catch (Exception ex) {
|
|
213
|
-
throw new Exception("Could not create redirect uri from package name and signature hash", ex);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
@ReactMethod
|
|
218
|
-
public void acquireToken(ReadableMap params, Promise promise) {
|
|
219
|
-
try {
|
|
220
|
-
AcquireTokenParameters.Builder acquireTokenParameters =
|
|
221
|
-
new AcquireTokenParameters.Builder()
|
|
222
|
-
.startAuthorizationFromActivity(this.getCurrentActivity());
|
|
223
|
-
|
|
224
|
-
// Required parameters
|
|
225
|
-
List<String> scopes = readableArrayToStringList(params.getArray("scopes"));
|
|
226
|
-
acquireTokenParameters.withScopes(scopes);
|
|
227
|
-
|
|
228
|
-
// Optional parameters
|
|
229
|
-
if (params.hasKey("authority")) {
|
|
230
|
-
acquireTokenParameters.fromAuthority(params.getString("authority"));
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (params.hasKey("promptType")) {
|
|
234
|
-
acquireTokenParameters.withPrompt(Prompt.values()[params.getInt("promptType")]);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (params.hasKey("loginHint")) {
|
|
238
|
-
acquireTokenParameters.withLoginHint(params.getString("loginHint"));
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (params.hasKey("extraScopesToConsent")) {
|
|
242
|
-
acquireTokenParameters.withOtherScopesToAuthorize(
|
|
243
|
-
readableArrayToStringList(params.getArray("extraScopesToConsent")));
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (params.hasKey("extraQueryParameters")) {
|
|
247
|
-
List<Map.Entry<String, String>> parameters = new ArrayList<>();
|
|
248
|
-
for (Map.Entry<String, Object> entry :
|
|
249
|
-
params.getMap("extraQueryParameters").toHashMap().entrySet()) {
|
|
250
|
-
parameters.add(new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue().toString()));
|
|
251
|
-
}
|
|
252
|
-
acquireTokenParameters.withAuthorizationQueryStringParameters(parameters);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
acquireTokenParameters.withCallback(getAuthInteractiveCallback(promise));
|
|
256
|
-
publicClientApplication.acquireToken(acquireTokenParameters.build());
|
|
257
|
-
} catch (Exception e) {
|
|
258
|
-
promise.reject(e);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
private AuthenticationCallback getAuthInteractiveCallback(Promise promise) {
|
|
263
|
-
return new AuthenticationCallback() {
|
|
264
|
-
@Override
|
|
265
|
-
public void onCancel() {
|
|
266
|
-
promise.reject("userCancel", "userCancel");
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
@Override
|
|
270
|
-
public void onSuccess(IAuthenticationResult authenticationResult) {
|
|
271
|
-
if (authenticationResult != null) {
|
|
272
|
-
promise.resolve(msalResultToDictionary(authenticationResult));
|
|
273
|
-
} else {
|
|
274
|
-
promise.resolve(null);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
@Override
|
|
279
|
-
public void onError(MsalException exception) {
|
|
280
|
-
promise.reject(exception);
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
@ReactMethod
|
|
286
|
-
public void acquireTokenSilent(ReadableMap params, Promise promise) {
|
|
287
|
-
try {
|
|
288
|
-
AcquireTokenSilentParameters.Builder acquireTokenSilentParameters =
|
|
289
|
-
new AcquireTokenSilentParameters.Builder();
|
|
290
|
-
|
|
291
|
-
// Required parameters
|
|
292
|
-
List<String> scopes = readableArrayToStringList(params.getArray("scopes"));
|
|
293
|
-
acquireTokenSilentParameters.withScopes(scopes);
|
|
294
|
-
|
|
295
|
-
ReadableMap accountIn = params.getMap("account");
|
|
296
|
-
String accountIdentifier = accountIn.getString("identifier");
|
|
297
|
-
IAccount account = publicClientApplication.getAccount(accountIdentifier);
|
|
298
|
-
acquireTokenSilentParameters.forAccount(account);
|
|
299
|
-
|
|
300
|
-
// Optional parameters
|
|
301
|
-
String authority =
|
|
302
|
-
publicClientApplication
|
|
303
|
-
.getConfiguration()
|
|
304
|
-
.getDefaultAuthority()
|
|
305
|
-
.getAuthorityURL()
|
|
306
|
-
.toString();
|
|
307
|
-
if (params.hasKey("authority")) {
|
|
308
|
-
authority = params.getString("authority");
|
|
309
|
-
}
|
|
310
|
-
acquireTokenSilentParameters.fromAuthority(authority);
|
|
311
|
-
|
|
312
|
-
if (params.hasKey("forceRefresh")) {
|
|
313
|
-
acquireTokenSilentParameters.forceRefresh(params.getBoolean("forceRefresh"));
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
acquireTokenSilentParameters.withCallback(getAuthSilentCallback(promise));
|
|
317
|
-
publicClientApplication.acquireTokenSilentAsync(acquireTokenSilentParameters.build());
|
|
318
|
-
} catch (Exception e) {
|
|
319
|
-
promise.reject(e);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
private SilentAuthenticationCallback getAuthSilentCallback(Promise promise) {
|
|
324
|
-
return new SilentAuthenticationCallback() {
|
|
325
|
-
@Override
|
|
326
|
-
public void onSuccess(IAuthenticationResult authenticationResult) {
|
|
327
|
-
if (authenticationResult != null) {
|
|
328
|
-
promise.resolve(msalResultToDictionary(authenticationResult));
|
|
329
|
-
} else {
|
|
330
|
-
promise.resolve(null);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
@Override
|
|
335
|
-
public void onError(MsalException exception) {
|
|
336
|
-
promise.reject(exception);
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
@ReactMethod
|
|
342
|
-
public void getAccounts(Promise promise) {
|
|
343
|
-
try {
|
|
344
|
-
List<IAccount> accounts = publicClientApplication.getAccounts();
|
|
345
|
-
WritableArray array = Arguments.createArray();
|
|
346
|
-
if (accounts != null) {
|
|
347
|
-
for (IAccount account : accounts) {
|
|
348
|
-
array.pushMap(accountToMap(account));
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
promise.resolve(array);
|
|
352
|
-
} catch (Exception e) {
|
|
353
|
-
promise.reject(e);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
@ReactMethod
|
|
358
|
-
public void getAccount(String accountIdentifier, Promise promise) {
|
|
359
|
-
try {
|
|
360
|
-
IAccount account = publicClientApplication.getAccount(accountIdentifier);
|
|
361
|
-
if (account != null) {
|
|
362
|
-
promise.resolve(accountToMap(account));
|
|
363
|
-
} else {
|
|
364
|
-
promise.resolve(null);
|
|
365
|
-
}
|
|
366
|
-
} catch (Exception e) {
|
|
367
|
-
promise.reject(e);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
@ReactMethod
|
|
372
|
-
public void removeAccount(ReadableMap accountIn, Promise promise) {
|
|
373
|
-
try {
|
|
374
|
-
// Required parameters
|
|
375
|
-
String accountIdentifier = accountIn.getString(("identifier"));
|
|
376
|
-
IAccount account = publicClientApplication.getAccount(accountIdentifier);
|
|
377
|
-
|
|
378
|
-
publicClientApplication.removeAccount(
|
|
379
|
-
account,
|
|
380
|
-
new IMultipleAccountPublicClientApplication.RemoveAccountCallback() {
|
|
381
|
-
@Override
|
|
382
|
-
public void onRemoved() {
|
|
383
|
-
promise.resolve(true);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
@Override
|
|
387
|
-
public void onError(@NonNull MsalException exception) {
|
|
388
|
-
promise.reject(exception);
|
|
389
|
-
}
|
|
390
|
-
});
|
|
391
|
-
} catch (Exception e) {
|
|
392
|
-
promise.reject(e);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
private WritableMap msalResultToDictionary(@NonNull IAuthenticationResult result) {
|
|
397
|
-
WritableMap map = Arguments.createMap();
|
|
398
|
-
map.putString("accessToken", result.getAccessToken());
|
|
399
|
-
map.putString("expiresOn", String.format("%s", result.getExpiresOn().getTime() / 1000));
|
|
400
|
-
String idToken = result.getAccount().getIdToken();
|
|
401
|
-
if (idToken == null) {
|
|
402
|
-
idToken = ((IMultiTenantAccount) result.getAccount()).getTenantProfiles().get(result.getTenantId()).getIdToken();
|
|
403
|
-
}
|
|
404
|
-
map.putString("idToken", idToken);
|
|
405
|
-
map.putArray("scopes", Arguments.fromArray(result.getScope()));
|
|
406
|
-
map.putString("tenantId", result.getTenantId());
|
|
407
|
-
map.putMap("account", accountToMap(result.getAccount()));
|
|
408
|
-
return map;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
private WritableMap accountToMap(@NonNull IAccount account) {
|
|
412
|
-
WritableMap map = Arguments.createMap();
|
|
413
|
-
map.putString("identifier", account.getId());
|
|
414
|
-
map.putString("username", account.getUsername());
|
|
415
|
-
map.putString("tenantId", account.getTenantId());
|
|
416
|
-
Map<String, ?> claims = account.getClaims();
|
|
417
|
-
if (claims != null) {
|
|
418
|
-
map.putMap("claims", toWritableMap(claims));
|
|
419
|
-
}
|
|
420
|
-
return map;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
@NonNull
|
|
425
|
-
private List<String> readableArrayToStringList(@Nullable ReadableArray readableArray) {
|
|
426
|
-
List<String> list = new ArrayList<>();
|
|
427
|
-
if (readableArray != null) {
|
|
428
|
-
for (Object item : readableArray.toArrayList()) {
|
|
429
|
-
list.add(item.toString());
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
return list;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
@NonNull
|
|
436
|
-
private WritableMap toWritableMap(@NonNull Map<String, ?> map) {
|
|
437
|
-
WritableMap writableMap = Arguments.createMap();
|
|
438
|
-
for (Map.Entry<String, ?> entry : map.entrySet()) {
|
|
439
|
-
String key = entry.getKey();
|
|
440
|
-
Object value = entry.getValue();
|
|
441
|
-
if (value == null) {
|
|
442
|
-
writableMap.putNull(key);
|
|
443
|
-
} else if (value instanceof Boolean) {
|
|
444
|
-
writableMap.putBoolean(key, (Boolean) value);
|
|
445
|
-
} else if (value instanceof Double) {
|
|
446
|
-
writableMap.putDouble(key, (Double) value);
|
|
447
|
-
} else if (value instanceof Integer) {
|
|
448
|
-
writableMap.putInt(key, (Integer) value);
|
|
449
|
-
} else if (value instanceof String) {
|
|
450
|
-
writableMap.putString(key, (String) value);
|
|
451
|
-
} else if (value instanceof Map<?, ?>) {
|
|
452
|
-
writableMap.putMap(key, toWritableMap((Map<String, ?>) value));
|
|
453
|
-
} else if (value instanceof List<?>) {
|
|
454
|
-
writableMap.putArray(key, toWritableArray((List<?>) value));
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
return writableMap;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
@NonNull
|
|
461
|
-
private WritableArray toWritableArray(@NonNull List<?> list) {
|
|
462
|
-
WritableArray writableArray = Arguments.createArray();
|
|
463
|
-
for (Object value : list.toArray()) {
|
|
464
|
-
if (value == null) {
|
|
465
|
-
writableArray.pushNull();
|
|
466
|
-
} else if (value instanceof Boolean) {
|
|
467
|
-
writableArray.pushBoolean((Boolean) value);
|
|
468
|
-
} else if (value instanceof Double) {
|
|
469
|
-
writableArray.pushDouble((Double) value);
|
|
470
|
-
} else if (value instanceof Integer) {
|
|
471
|
-
writableArray.pushInt((Integer) value);
|
|
472
|
-
} else if (value instanceof String) {
|
|
473
|
-
writableArray.pushString((String) value);
|
|
474
|
-
} else if (value instanceof Map<?, ?>) {
|
|
475
|
-
writableArray.pushMap(toWritableMap((Map<String, ?>) value));
|
|
476
|
-
} else if (value instanceof List<?>) {
|
|
477
|
-
writableArray.pushArray(toWritableArray((List<?>) value));
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
return writableArray;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
package com.reactnativemsal;
|
|
2
|
-
|
|
3
|
-
import androidx.annotation.NonNull;
|
|
4
|
-
|
|
5
|
-
import com.facebook.react.ReactPackage;
|
|
6
|
-
import com.facebook.react.bridge.NativeModule;
|
|
7
|
-
import com.facebook.react.bridge.ReactApplicationContext;
|
|
8
|
-
import com.facebook.react.uimanager.ViewManager;
|
|
9
|
-
|
|
10
|
-
import java.util.Collections;
|
|
11
|
-
import java.util.List;
|
|
12
|
-
|
|
13
|
-
public class RNMSALPackage implements ReactPackage {
|
|
14
|
-
@NonNull
|
|
15
|
-
@Override
|
|
16
|
-
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
|
|
17
|
-
return Collections.singletonList(new RNMSALModule(reactContext));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
@NonNull
|
|
21
|
-
@Override
|
|
22
|
-
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
|
|
23
|
-
return Collections.emptyList();
|
|
24
|
-
}
|
|
25
|
-
}
|