azure-activedirectory-library-for-objc icon indicating copy to clipboard operation
azure-activedirectory-library-for-objc copied to clipboard

Problem with NSURLRequest caching and ADURLProtocol on macOS

Open macblazer opened this issue 7 years ago • 7 comments

I am using the ADAL v2.5.1 release from Swift developing with the macOS 10.12 SDK and running on macOS 10.12.6. When I use it like so (no other code related to caching anywhere):

let authContext = ADAuthenticationContext(authority: authorityURL, error: error)
authContext.acquireToken(withResource: AZURE_RESOURCE_ID,
                                 clientId: clientId,
                                 redirectUri: URL(string: AZURE_REDIRECT_URL_STRING),
                                 userId: nil,
                                 extraQueryParameters: queryParams,
                                 completionBlock: { (result) in
                                 // use result here
                                 })

I get the following errors logged:

ERROR: createEncodedCachedResponseAndRequestForXPCTransmission - Invalid protocol-property list - CFURLRequestRef. protoProps=<CFBasicHash 0x7fd6dc71d050 [0x7fffa1a9cda0]>{type = mutable dict, count = 1,
entries =>
	0 : <CFString 0x105b12210 [0x7fffa1a9cda0]>{contents = "context"} = <ADWebAuthRequest: 0x7fd6dc7180d0>
}
ADD: failed to create cache dictionary at path=/Users/<mylocalacct>/Library/Caches/<mybundleid>. key=0x7fd6dc71a590

This appears to be a problem with NSURLRequest caching and the ADURLProtocol putting the context as a property into NSURLProtocol in the +addContext:toRequest: method in ADURLProtocol.m line 106: [NSURLProtocol setProperty:context forKey:@"context" inRequest:request]. This value is retrieved at line 42: [NSURLProtocol propertyForKey:@"context" inRequest:request].

Some StackOverflow posts seem to indicate that objects given to NSURLProtocol's setProperty:forKey:inRequest: should be property list serializable, although that's not explicitly stated in Apple's documentation. Can the caching be disabled somehow, or the property data be encoded/decoded for use in the context property?

macblazer avatar Aug 07 '17 17:08 macblazer

@unpluggedk Can you take a look at this, when you have time?

oldalton avatar Oct 12 '17 18:10 oldalton

@macblazer Can you give me some more detail? I've tried to repro this, and was not successful on macOS 10.12.6 with ADAL v2.5.1 on Swift.

  • Does it always happen and when does it happen? (i.e./ Do you need to run it multiple times or happens at the first go)
  • What is in the extraQueryParameters?

Any other information for me to reproduce this would be very helpful.

Thanks

unpluggedk avatar Oct 13 '17 18:10 unpluggedk

It happens every time I call that authContext.acquireToken function when it has to pop open a window.

I am using the ADTokenCacheDelegate protocol to save tokens between launches. If it has the cached token, then no window is shown and the warning doesn't appear. If the cache is empty or expired, the window to login opens up and the warning message is shown.

I use this little function to come up with the String for extraQueryParameters.

    func extraQueryParameters(forDomain tenantDomain: String) -> String {
        let claims = "{\"access_token\":{\"deviceid\":{\"essential\":true}}}"
        let encodedClaims = claims.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
        let encodedDomain = tenantDomain.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)

        return "claims=\(encodedClaims!)&domain_hint=\(encodedDomain!)"
    }

macblazer avatar Nov 01 '17 19:11 macblazer

@macblazer, @unpluggedk, is there any development on this issue? I'm experiencing the very same issue on ADAL 2.5.3 while developing an iOS App (Swift 4/ Xcode 9.2).

Here's how I get the token from AAD (as seen in Microsoft's Guides):

func getToken(clearCache: Bool, parent: UIViewController, completion: @escaping (_ userInfo: ADUserInformation?, _ error: NSError?) -> Void)
    {
        let error: AutoreleasingUnsafeMutablePointer<ADAuthenticationError?>? = nil
        var authenticationContext: ADAuthenticationContext
        
        authenticationContext = ADAuthenticationContext(authority: config.authority!, error: error)
        authenticationContext.parentController = parent
        
        
        authenticationContext.acquireToken(
            withResource: config.resource!,
            clientId: config.clientId,
            redirectUri: URL(string: config.redirectUri!),
            promptBehavior: AD_PROMPT_AUTO,
            userId: nil,
            extraQueryParameters: "nux=1" ) { [weak self] optResult in
                
                if let result = optResult {
                    if result.status != AD_SUCCEEDED {
                        print("Error: \(result.error.errorDetails)")
                        completion(nil, (result.error)!)
                    } else {
                        self?.token = result.accessToken
                        self?.username = (result.tokenCacheItem.userInformation?.userId)!
                        
                        completion(result.tokenCacheItem.userInformation, nil)
                    }
                } else {
                    print("Error: no result from token call")
                }
        }
    }

Since it works more like a warning, I've been ignoring this error for now, but I'd like to know if there's something I could do to fix it

jotabe87 avatar Jan 04 '18 07:01 jotabe87

2.5.4 as well on iOS App (Swift 4/ Xcode 9.2).

It actually appears to not even be popping up the window to put in a password but I'm unsure if this is in relation to another issue in my code.

This is my code:


     func getToken(username: String, completionBlock: @escaping (String) -> Void){
        let error: AutoreleasingUnsafeMutablePointer<ADAuthenticationError?>? = nil
        let authContext = ADAuthenticationContext(authority: "https://login.microsoftonline.com/common", error: error)

        authContext?.acquireToken(withResource: "https://graph.windows.net", clientId: clientID, redirectUri: redirectURI, userId: username, completionBlock: { (result: ADAuthenticationResult!) in
            if (AD_SUCCEEDED != result.status){
                let loginFail = UIAlertController(title: "Login Failed", message: result.error.errorDetails, preferredStyle: .alert)
                let retry = UIAlertAction(title: "Retry", style: .cancel, handler: { (UIAlertAction) in self.getToken(username: username, completionBlock: completionBlock)})
                loginFail.addAction(retry)
                if self.window?.rootViewController is LoginViewController{
                    self.window?.rootViewController?.present(loginFail, animated: true, completion: nil)
                }
                else{
                    (self.window?.rootViewController as! UINavigationController).topViewController?.present(loginFail, animated: true, completion: nil)
                }
            }
            else{
                completionBlock(result.accessToken);
            }
        })
    }

TeddyCodeDev avatar Jan 05 '18 04:01 TeddyCodeDev

This seems to be happening because of carrying the whole request context in ADURLProtocol:

[NSURLProtocol setProperty:context forKey:@"context" inRequest:request];

This can be fixed by either making sure request context is compatible with NSURLProtocol or saving only correlationId for logging purposes. This has to be done on ADAL side.

oldalton avatar Jan 21 '18 21:01 oldalton

Hi, I am using ADAL 2.7.7 and IntuneMAM SDK for IOS application.
Intune policy works for the first time after which when uninstalled and installed the app it does not work

It give below error:

ERROR: createEncodedCachedResponseAndRequestForXPCTransmission - Invalid protocol-property list - CFURLRequestRef. protoProps=<CFBasicHash 0x7fd6dc71d050 [0x7fffa1a9cda0]>{type = mutable dict, count = 1,

I used the Intune wrapping tool which has ADAL version 2.6.3 it gives different error ADAL 2.6.3 iOS 12.1.4 [2019-02-19 17:57:59] INFO: Found 2 token(s) for query

AnilKumar09 avatar Feb 19 '19 19:02 AnilKumar09