Skip to content

Commit

Permalink
Merge pull request #2087 from AzureAD/release/1.3.1
Browse files Browse the repository at this point in the history
Release 1.3.1
  • Loading branch information
mipetriu authored Mar 14, 2024
2 parents f3f84a6 + c847a89 commit 9eedec7
Show file tree
Hide file tree
Showing 36 changed files with 216 additions and 133 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## [1.3.1]
* Preferred auth method added to device information, returned from broker

## [1.3.0]

## [1.2.22]
Expand Down
2 changes: 1 addition & 1 deletion MSAL.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "MSAL"
s.version = "1.3.0"
s.version = "1.3.1"
s.summary = "Microsoft Authentication Library (MSAL) for iOS"
s.description = <<-DESC
The MSAL library for iOS gives your app the ability to begin using the Microsoft Cloud by supporting Microsoft Azure Active Directory and Microsoft Accounts in a converged experience using industry standard OAuth2 and OpenID Connect. The library also supports Microsoft Azure B2C for those using our hosted identity management service.
Expand Down
2 changes: 1 addition & 1 deletion MSAL/IdentityCore
4 changes: 4 additions & 0 deletions MSAL/MSAL.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@
23FB5C1E22542B99002BF1EB /* MSALJsonDeserializable.h in Headers */ = {isa = PBXBuildFile; fileRef = 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */; settings = {ATTRIBUTES = (Public, ); }; };
2826932A2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */; };
2826933B2A0B98750037B93A /* MSALNativeAuthSignInParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2826933A2A0B98750037B93A /* MSALNativeAuthSignInParameters.swift */; };
285D0D692B99C14F002A1D4A /* MSALNativeAuthTokenResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285D0D682B99C14F002A1D4A /* MSALNativeAuthTokenResult.swift */; };
285F36082A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */; };
2877081F2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */; };
287708222A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */; };
Expand Down Expand Up @@ -1540,6 +1541,7 @@
23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALJsonDeserializable.h; sourceTree = "<group>"; };
282693272A0974740037B93A /* MSALNativeAuthTokenRequestParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenRequestParameters.swift; sourceTree = "<group>"; };
2826933A2A0B98750037B93A /* MSALNativeAuthSignInParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInParameters.swift; sourceTree = "<group>"; };
285D0D682B99C14F002A1D4A /* MSALNativeAuthTokenResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthTokenResult.swift; sourceTree = "<group>"; };
285F36072A24DF8300A2190F /* MSALNativeAuthSignInControlling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInControlling.swift; sourceTree = "<group>"; };
2877081E2A14F67400E371ED /* MSALNativeAuthSignInChallengeValidatedResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthSignInChallengeValidatedResponse.swift; sourceTree = "<group>"; };
287708212A151A8500E371ED /* MSALNativeAuthInternalChannelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSALNativeAuthInternalChannelType.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3941,6 +3943,7 @@
9BD78D7A2A126A1500AA7E12 /* MSALNativeAuthChallengeTypes.h */,
DE8BE7DB2A1F6BD2009642A5 /* MSALNativeAuthUserAccountResult.swift */,
E2D3BC4E2A7BE1C4009C4D1F /* MSALNativeAuthUserAccountResult+Internal.swift */,
285D0D682B99C14F002A1D4A /* MSALNativeAuthTokenResult.swift */,
);
path = public;
sourceTree = "<group>";
Expand Down Expand Up @@ -5791,6 +5794,7 @@
E2F626A72A780F3D00C4A303 /* SignUpStates+Internal.swift in Sources */,
2826932A2A0974750037B93A /* MSALNativeAuthTokenRequestParameters.swift in Sources */,
28EDF93E29E6D43900A99F2A /* SignUpStartError.swift in Sources */,
285D0D692B99C14F002A1D4A /* MSALNativeAuthTokenResult.swift in Sources */,
DE94C9F029F2AF5E00C1EC1F /* MSALNativeAuthResetPasswordChallengeRequestParameters.swift in Sources */,
D61BD2B31EBD09F90007E484 /* MSALPromptType.m in Sources */,
DEC1E425298BE18A00948BED /* MSALNativeAuthServerTelemetry.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion MSAL/resources/ios/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.3.0</string>
<string>1.3.1</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
Expand Down
2 changes: 1 addition & 1 deletion MSAL/resources/mac/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.3.0</string>
<string>1.3.1</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
Expand Down
13 changes: 13 additions & 0 deletions MSAL/src/MSALDeviceInformation.m
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ - (instancetype)initWithMSIDDeviceInfo:(MSIDDeviceInfo *)deviceInfo
#if TARGET_OS_OSX
_platformSSOStatus = [self msalPlatformSSOStatusFromMSIDPlatformSSOStatus:deviceInfo.platformSSOStatus];
#endif
_configuredPreferredAuthMethod = [self msalPreferredAuthMethodFromMSIDPreferredAuthMethod:deviceInfo.preferredAuthConfig];

_extraDeviceInformation = [NSMutableDictionary new];
[self initExtraDeviceInformation:deviceInfo];
}
Expand Down Expand Up @@ -134,6 +136,17 @@ - (MSALPlatformSSOStatus)msalPlatformSSOStatusFromMSIDPlatformSSOStatus:(MSIDPla
}
}

- (MSALPreferredAuthMethod)msalPreferredAuthMethodFromMSIDPreferredAuthMethod:(MSIDPreferredAuthMethod)msidPreferredAuthConfig
{
switch (msidPreferredAuthConfig) {
case MSIDPreferredAuthMethodQRPIN:
return 1; // Private enum value for QR+PIN

default:
return MSALPreferredAuthMethodNone;
}
}

// For readability, both keys and values in the output dictionary are NSString
- (void) initExtraDeviceInformation:(MSIDDeviceInfo *)deviceInfo
{
Expand Down
8 changes: 8 additions & 0 deletions MSAL/src/MSALPublicClientApplication.m
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,14 @@ - (void)acquireTokenWithParameters:(MSALInteractiveTokenParameters *)parameters
// Extra parameters to be added to the /authorize endpoint.
msidParams.extraAuthorizeURLQueryParameters = self.internalConfig.extraQueryParameters.extraAuthorizeURLQueryParameters;

// Private enum value for QR+PIN
if (parameters.preferredAuthMethod == 1)
{
NSMutableDictionary *extraAuthorizeURLQueryParameters = [msidParams.extraAuthorizeURLQueryParameters mutableCopy];
[extraAuthorizeURLQueryParameters setObject:MSID_PREFERRED_AUTH_METHOD_QR_PIN forKey:MSID_PREFERRED_AUTH_METHOD_KEY];
msidParams.extraAuthorizeURLQueryParameters = extraAuthorizeURLQueryParameters;
}

// Extra parameters to be added to the /token endpoint.
msidParams.extraTokenRequestParameters = self.internalConfig.extraQueryParameters.extraTokenURLParameters;

Expand Down
2 changes: 1 addition & 1 deletion MSAL/src/MSAL_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

#define MSAL_VER_HIGH 1
#define MSAL_VER_LOW 3
#define MSAL_VER_PATCH 0
#define MSAL_VER_PATCH 1

#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
Expand Down
4 changes: 2 additions & 2 deletions MSAL/src/native_auth/cache/MSALNativeAuthTokens.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
@_implementationOnly import MSAL_Private

class MSALNativeAuthTokens {
let accessToken: MSIDAccessToken?
let accessToken: MSIDAccessToken
let refreshToken: MSIDRefreshToken?
let rawIdToken: String?

init(accessToken: MSIDAccessToken?, refreshToken: MSIDRefreshToken?, rawIdToken: String?) {
init(accessToken: MSIDAccessToken, refreshToken: MSIDRefreshToken?, rawIdToken: String?) {
self.accessToken = accessToken
self.refreshToken = refreshToken
self.rawIdToken = rawIdToken
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,15 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController,
func refreshToken(context: MSALNativeAuthRequestContext, authTokens: MSALNativeAuthTokens) async -> RefreshTokenCredentialControllerResponse {
MSALLogger.log(level: .verbose, context: context, format: "Refresh started")
let telemetryEvent = makeAndStartTelemetryEvent(id: .telemetryApiIdRefreshToken, context: context)
let scopes = authTokens.accessToken?.scopes.array as? [String] ?? []
let scopes = authTokens.accessToken.scopes.array as? [String] ?? []
guard let request = createRefreshTokenRequest(
scopes: scopes,
refreshToken: authTokens.refreshToken?.refreshToken,
context: context
) else {
stopTelemetryEvent(telemetryEvent, context: context, error: MSALNativeAuthInternalError.invalidRequest)
return .init(
.failure(RetrieveAccessTokenError(type: .generalError, correlationId: context.correlationId())),
.failure(RetrieveAccessTokenError(type: .generalError, correlationId: context.correlationId())),
correlationId: context.correlationId()
)
}
Expand Down Expand Up @@ -181,8 +181,13 @@ final class MSALNativeAuthCredentialsController: MSALNativeAuthTokenController,
level: .verbose,
context: context,
format: "Refresh Token completed successfully")
// TODO: Handle tokenResult.refreshToken as? MSIDRefreshToken in a safer way
return .init(
.success(tokenResult.accessToken.accessToken),
.success(MSALNativeAuthTokenResult(authTokens: MSALNativeAuthTokens(
accessToken: tokenResult.accessToken,
refreshToken: tokenResult.refreshToken as? MSIDRefreshToken,
rawIdToken: tokenResult.rawIdToken
))),
correlationId: context.correlationId(),
telemetryUpdate: { [weak self] result in
telemetryEvent?.setUserInformation(tokenResult.account)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
import Foundation

protocol MSALNativeAuthCredentialsControlling {
typealias RefreshTokenCredentialControllerResponse = MSALNativeAuthControllerTelemetryWrapper<Result<String, RetrieveAccessTokenError>>
typealias RefreshTokenCredentialControllerResponse =
MSALNativeAuthControllerTelemetryWrapper<Result<MSALNativeAuthTokenResult, RetrieveAccessTokenError>>

func retrieveUserAccountResult(context: MSALNativeAuthRequestContext) -> MSALNativeAuthUserAccountResult?
func refreshToken(context: MSALNativeAuthRequestContext, authTokens: MSALNativeAuthTokens) async -> RefreshTokenCredentialControllerResponse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ enum MSALNativeAuthErrorMessage {
static let generalError = "General error"
static let invalidCode = "Invalid code"
static let refreshTokenExpired = "Refresh token is expired"
static let tokenNotFound = "Token not found"
static let redirectUriNotSetWarning = "WARNING ⚠️: redirectUri not set during MSAL Native Auth initialization. Production apps must correctly configure a redirect URI and call acquireToken in response to all browserRequired errors. See https://learn.microsoft.com/entra/identity-platform/redirect-uris-ios"
static let unexpectedResponseBody = "Unexpected response body received"
static let unexpectedChallengeType = "Unexpected challenge type"
Expand Down
53 changes: 53 additions & 0 deletions MSAL/src/native_auth/public/MSALNativeAuthTokenResult.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import Foundation

public class MSALNativeAuthTokenResult: NSObject {

let authTokens: MSALNativeAuthTokens

init(authTokens: MSALNativeAuthTokens) {
self.authTokens = authTokens
}

/**
The Access Token requested.
Note that if access token is not returned in token response, this property will be returned as an empty string.
*/
@objc public var accessToken: String {
authTokens.accessToken.accessToken
}

/// Get the list of permissions for the access token for the account.
@objc public var scopes: [String] {
authTokens.accessToken.scopes.array as? [String] ?? []
}

/// Get the expiration date for the access token for the account.
/// This value is calculated based on current UTC time measured locally and the value expiresIn returned from the service
@objc public var expiresOn: Date? {
authTokens.accessToken.expiresOn
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,12 @@ extension MSALNativeAuthUserAccountResult {
let context = MSALNativeAuthRequestContext(correlationId: correlationId)
let correlationId = context.correlationId()

if let accessToken = self.authTokens.accessToken {
if forceRefresh || accessToken.isExpired() {
let controllerFactory = MSALNativeAuthControllerFactory(config: configuration)
let credentialsController = controllerFactory.makeCredentialsController(cacheAccessor: cacheAccessor)
return await credentialsController.refreshToken(context: context, authTokens: authTokens)
} else {
return .init(.success(accessToken.accessToken), correlationId: correlationId)
}
if forceRefresh || self.authTokens.accessToken.isExpired() {
let controllerFactory = MSALNativeAuthControllerFactory(config: configuration)
let credentialsController = controllerFactory.makeCredentialsController(cacheAccessor: cacheAccessor)
return await credentialsController.refreshToken(context: context, authTokens: authTokens)
} else {
MSALLogger.log(level: .error, context: context, format: "Retrieve Access Token: Existing token not found")
return .init(.failure(RetrieveAccessTokenError(type: .tokenNotFound, correlationId: correlationId)), correlationId: correlationId)
return .init(.success(MSALNativeAuthTokenResult(authTokens: authTokens)), correlationId: correlationId)
}
}
}
14 changes: 2 additions & 12 deletions MSAL/src/native_auth/public/MSALNativeAuthUserAccountResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,6 @@ import Foundation
authTokens.rawIdToken
}

/// Get the list of permissions for the access token for the account if present.
@objc public var scopes: [String] {
authTokens.accessToken?.scopes.array as? [String] ?? []
}

/// Get the expiration date for the access token for the account if present.
@objc public var expiresOn: Date? {
authTokens.accessToken?.expiresOn
}

init(
account: MSALAccount,
authTokens: MSALNativeAuthTokens,
Expand Down Expand Up @@ -96,9 +86,9 @@ import Foundation
let delegateDispatcher = CredentialsDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)

switch controllerResponse.result {
case .success(let accessToken):
case .success(let accessTokenResult):
await delegateDispatcher.dispatchAccessTokenRetrieveCompleted(
accessToken: accessToken,
result: accessTokenResult,
correlationId: controllerResponse.correlationId
)
case .failure(let error):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ public protocol CredentialsDelegate {

/// Notifies the delegate that the operation completed successfully.
/// - Note: If a flow requires this optional method and it is not implemented, then ``onAccessTokenRetrieveError(error:)`` will be called.
/// - Parameter accessToken: The access token string.
@MainActor @objc optional func onAccessTokenRetrieveCompleted(accessToken: String)
/// - Parameter result: The access token result.
@MainActor @objc optional func onAccessTokenRetrieveCompleted(result: MSALNativeAuthTokenResult)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ import Foundation

final class CredentialsDelegateDispatcher: DelegateDispatcher<CredentialsDelegate> {

func dispatchAccessTokenRetrieveCompleted(accessToken: String, correlationId: UUID) async {
func dispatchAccessTokenRetrieveCompleted(result: MSALNativeAuthTokenResult, correlationId: UUID) async {
if let onAccessTokenRetrieveCompleted = delegate.onAccessTokenRetrieveCompleted {
telemetryUpdate?(.success(()))
await onAccessTokenRetrieveCompleted(accessToken)
await onAccessTokenRetrieveCompleted(result)
} else {
let error = RetrieveAccessTokenError(
type: .generalError,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ public class RetrieveAccessTokenError: MSALNativeAuthError {
enum ErrorType: CaseIterable {
case browserRequired
case refreshTokenExpired
case tokenNotFound
case generalError
}

Expand All @@ -52,8 +51,6 @@ public class RetrieveAccessTokenError: MSALNativeAuthError {
return MSALNativeAuthErrorMessage.browserRequired
case .refreshTokenExpired:
return MSALNativeAuthErrorMessage.refreshTokenExpired
case .tokenNotFound:
return MSALNativeAuthErrorMessage.tokenNotFound
case .generalError:
return MSALNativeAuthErrorMessage.generalError
}
Expand All @@ -68,9 +65,4 @@ public class RetrieveAccessTokenError: MSALNativeAuthError {
public var isRefreshTokenExpired: Bool {
return type == .refreshTokenExpired
}

/// Returns `true` if the existing token cannot be found.
public var isTokenNotFound: Bool {
return type == .tokenNotFound
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ public class SignUpBaseState: MSALNativeAuthBaseState {
public func submitCode(code: String, delegate: SignUpVerifyCodeDelegate) {
Task {
let controllerResponse = await submitCodeInternal(code: code)

let delegateDispatcher = SignUpVerifyCodeDelegateDispatcher(delegate: delegate, telemetryUpdate: controllerResponse.telemetryUpdate)

switch controllerResponse.result {
Expand Down
12 changes: 12 additions & 0 deletions MSAL/src/public/MSALDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,18 @@ typedef NS_ENUM(NSUInteger, MSALPlatformSSOStatus)
MSALPlatformSSOEnabledAndRegistered
};

/**
Preferred auth method for MSAL requests. Can be configured by admin as part of MSALDeviceInformation and
passed in the interactive params to the server.
*/
typedef NS_ENUM(NSUInteger, MSALPreferredAuthMethod)
{
/*
No preferred auth method passed with the request to the authetication server.
*/
MSALPreferredAuthMethodNone
};

/**
The block that gets invoked after MSAL has finished getting a token silently or interactively.
@param result Represents information returned to the application after a successful interactive or silent token acquisition. See `MSALResult` for more information.
Expand Down
5 changes: 5 additions & 0 deletions MSAL/src/public/MSALDeviceInformation.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, readonly) MSALDeviceMode deviceMode;

/**
Availability of QR+PIN as an authentication method as configured by the admin
*/
@property (nonatomic, readonly) MSALPreferredAuthMethod configuredPreferredAuthMethod;

/**
Specifies whether AAD SSO extension was detected on the device.
*/
Expand Down
Loading

0 comments on commit 9eedec7

Please sign in to comment.