Skip to content
This repository has been archived by the owner on Jun 30, 2023. It is now read-only.

Commit

Permalink
Jennyf/ios13 (#1655)
Browse files Browse the repository at this point in the history
* Part 1: ios 13
- Generate a nonce to send in the broker request, only if msauthv3 (iOS broker 6.3.19+) is installed on the device
- Check that the nonce in the broker response matches the nonce sent in the request
- Update info.plist in dev app for msauthv3

* more updates

* pr feedback
  • Loading branch information
jennyf19 authored Sep 19, 2019
1 parent 36da690 commit 722ca62
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 10 deletions.
1 change: 1 addition & 0 deletions devApps/XFormsApp.iOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<key>LSApplicationQueriesSchemes</key>
<array>
<string>msauth</string>
<string>msauthv3</string>
</array>

<key>CFBundleURLTypes</key>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,11 @@ public static class AdalError
/// </summary>
public const string BrokerReponseHashMismatch = "broker_response_hash_mismatch";

/// <summary>
/// Broker response nonce does not match the request nonce sent by MSAL.NET for iOS broker >= v6.3.19
/// </summary>
public const string BrokerNonceMismatch = "broker_nonce_mismatch";

/// <summary>
/// Device certificate not found.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ internal static class AdalErrorMessage
public const string RedirectUriContainsFragment = "'redirectUri' must NOT include a fragment component";
public const string ServiceReturnedError = "Service returned error. Check InnerException for more details";
public const string BrokerReponseHashMismatch = "Unencrypted broker response hash did not match the expected hash";
public const string BrokerNonceMismatch = "Broker response nonce does not match the request nonce sent by MSAL.NET." +
"Please see https://aka.ms/adal-net-ios-13-broker for more details. ";

public const string StsMetadataRequestFailed =
"Metadata request to Access Control service failed. Check InnerException for more details";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Flows
{
Expand All @@ -21,5 +18,6 @@ internal static class BrokerParameter
public const string Claims = "claims";
public const string SilentBrokerFlow = "silent_broker_flow";
public const string BrokerInstallUrl = "broker_install_url";
public const string BrokerNonce = "broker_nonce";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
//------------------------------------------------------------------------------

using System;
using System.Diagnostics;
using Foundation;
using Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Platform;

Expand All @@ -44,7 +45,24 @@ public static class AuthenticationContinuationHelper
/// <returns>True if the response is from broker, False otherwise.</returns>
public static bool IsBrokerResponse(string sourceApplication)
{
return sourceApplication != null && sourceApplication.Equals("com.microsoft.azureauthenticator", StringComparison.OrdinalIgnoreCase);
Debug.WriteLine("IsBrokerResponse called with sourceApplication {0}", sourceApplication);

if (sourceApplication != null && sourceApplication.Equals("com.microsoft.azureauthenticator", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (string.IsNullOrEmpty(sourceApplication))
{
// For iOS 13+, SourceApplication will not be returned
// Customers will need to install iOS broker >= 6.3.19
// ADAL.NET will generate a nonce (guid), which broker will
// return in the response. ADAL.NET will validate a match in iOSBroker.cs
// So if SourceApplication is null, just return, ADAL.NET will throw a
// specific error message if the nonce does not match.
return true;
}

return false;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ internal class iOSBroker : IBroker

private readonly ICoreLogger _logger;

private string _brokerRequestNonce;
private bool _brokerV3Installed = false;

public iOSBroker(ICoreLogger logger)
{
_logger = logger;
Expand All @@ -66,21 +69,42 @@ public bool CanInvokeBroker
return false;
}

var res = false;
bool canStartBroker = false;

if (pp.UseBroker)
{
pp.CallerViewController.InvokeOnMainThread(() =>
{
res = UIApplication.SharedApplication.CanOpenUrl(new NSUrl("msauth://"));
_logger.Info("iOS Broker can be invoked. ");
if (IsBrokerInstalled("msauthv3://"))
{
_logger.Info("iOS Broker (msauthv3://) can be invoked. ");
_brokerV3Installed = true;
canStartBroker = true;
}
});

if (!canStartBroker)
{
pp.CallerViewController.InvokeOnMainThread(() =>
{
if (IsBrokerInstalled("msauth://"))
{
_logger.Info("iOS Broker (msauth://) can be invoked. ");
canStartBroker = true;
}
});
}
}

return res;
return canStartBroker;
}
}

private bool IsBrokerInstalled(string brokerUriScheme)
{
return UIApplication.SharedApplication.CanOpenUrl(new NSUrl(brokerUriScheme));
}

public async Task<AdalResultWrapper> AcquireTokenUsingBrokerAsync(IDictionary<string, string> brokerPayload)
{
if (brokerPayload.ContainsKey(BrokerParameter.SilentBrokerFlow))
Expand All @@ -105,6 +129,13 @@ public async Task<AdalResultWrapper> AcquireTokenUsingBrokerAsync(IDictionary<st
brokerPayload[BrokerParameter.Claims] = claims;
}

if (_brokerV3Installed)
{
_brokerRequestNonce = string.Empty;
_brokerRequestNonce = Guid.NewGuid().ToString();
brokerPayload[BrokerParameter.BrokerNonce] = _brokerRequestNonce;
}

if (brokerPayload.ContainsKey(BrokerParameter.BrokerInstallUrl))
{
string url = brokerPayload[BrokerParameter.BrokerInstallUrl];
Expand Down Expand Up @@ -172,6 +203,7 @@ private AdalResultWrapper ResultFromBrokerResponse(IDictionary<string, string> r
string responseActualHash = PlatformProxyFactory.GetPlatformProxy().CryptographyManager.CreateSha256Hash(decryptedResponse);
byte[] rawHash = Convert.FromBase64String(responseActualHash);
string hash = BitConverter.ToString(rawHash);

if (expectedHash.Equals(hash.Replace("-", ""), StringComparison.OrdinalIgnoreCase))
{
responseDictionary = EncodingHelper.ParseKeyValueList(decryptedResponse, '&', false, null);
Expand All @@ -187,13 +219,35 @@ private AdalResultWrapper ResultFromBrokerResponse(IDictionary<string, string> r
};
_logger.InfoPii("Broker response hash mismatch: " + response.Error, "Broker response hash mismatch. ");
}

if (!ValidateBrokerResponseNonceWithRequestNonce(responseDictionary))
{
response = new TokenResponse
{
Error = AdalError.BrokerReponseHashMismatch,
ErrorDescription = AdalErrorMessage.BrokerReponseHashMismatch
};
}
}

var dateTimeOffset = new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc));
dateTimeOffset = dateTimeOffset.AddSeconds(response.ExpiresOn);
return response.GetResult(dateTimeOffset, dateTimeOffset);
}

private bool ValidateBrokerResponseNonceWithRequestNonce(IDictionary<string, string> brokerResponseDictionary)
{
if (!string.IsNullOrEmpty(_brokerRequestNonce))
{
string brokerResponseNonce = brokerResponseDictionary.ContainsKey(BrokerParameter.BrokerNonce)
? brokerResponseDictionary[BrokerParameter.BrokerNonce]
: null;

return string.Equals(brokerResponseNonce, _brokerRequestNonce);
}
return false;
}

public static void SetBrokerResponse(NSUrl responseUrl)
{
brokerResponse = responseUrl;
Expand Down

0 comments on commit 722ca62

Please sign in to comment.