Closed helloniklas closed 7 years ago
Downloading the sample code again, they still seem to use DeveloperAuthenticatedIdentityProvider : AWSAbstractCognitoIdentityProvider. So not sure what to do here, I guess I just have to revert to the old 2.3.6, as getting this custom identity to work was very complex in the first place.
YES, same issue. the 2.4.0 version will break my production app.
I have a customerSignin Provider based on AWSEnhancedCognitoIdentityProvider
@interface CustomIdentityProvider : AWSEnhancedCognitoIdentityProvider
I hope there is a transition tutorial for the removed class. Thank you!
Same issue, just updated via cocoapods to 2.4.0
, I used the Cognito sample app to build off, I now have the following errors.
Fatal: Value of type 'AWSCognitoCredentialsProvider' has no member 'refresh'
https://github.com/awslabs/aws-sdk-ios-samples/blob/master/CognitoSync-Sample/Swift/CognitoSyncDemo/AmazonClientManager.swift#L130
Warning: 'logins' is deprecated: Use 'AWSIdentityProviderManager' to provide a valid logins dictionary to the credentials provider.
In 2 Lines:
https://github.com/awslabs/aws-sdk-ios-samples/blob/master/CognitoSync-Sample/Swift/CognitoSyncDemo/AmazonClientManager.swift#L118
It would be great if the samples could be updated to reflect the changes in 2.4.0
.
https://github.com/awslabs/aws-sdk-ios-samples https://github.com/awslabs/aws-sdk-ios-samples/tree/master/CognitoSync-Sample
I had a look at the changelog, It mentions the deprecated logins issue, but nothing about the Value of type 'AWSCognitoCredentialsProvider' has no member 'refresh'
Fatal error.
https://github.com/aws/aws-sdk-ios/blob/master/CHANGELOG.md
@yosuke-matsuda @aws-dpt @behrooziAWS Can someone spare a few mins to update the samples to reflect the new changes when you get a chance?
You can take a look at the implementation of AWSCognitoCredentialsProvider
and its use of AWSCognitoCredentialsProviderHelper
as a reference.
We are preparing the sample app updates, and it should be available soon. When we update our samples, we'll update this thread. Thanks.
I can't seem to figure this out. Where do I implement my previous refresh() method? Do I now have to build a AWSCognitoIdentityProviderRefreshTokensRequest instead? Hopefully your samples will help.
It's bit daunting that after spending so much time to get custom logins working with Lambda a point update has changed everything it seems. Especially considering this is something the competition is offering with zero implementation and is something almost every app will need, as relying on 3rd party logins is not feasible for a real life app.
breaking changes like this should not be a point update 👎. Dealing with this same issue myself. What makes it worse is documentation of this breaking change shouldve gone up with the 2.4.0 release :(.
Normal practice would have been to leave the deprecated method in there still working but flagged as depcricated. To sink the whole sdk like this I don't think is acceptable unless you're on a 0.9 release cycle.
Did anybody manage to do this? Cause i'm in need to implement it and i can't seem to figure out which methods should i implement of the provider, maybe i should return NO in the isAuthenticated method and then my getIdentityId will be called?
@guillecom you might want to go with the new user pools, although it's in beta only. https://mobile.awsblog.com/post/TxGNH1AUKDRZDH/Announcing-Your-User-Pools-in-Amazon-Cognito
Thanks for the advice, here is one that might shed some light on the original issue: The class we need to implement is
@protocol AWSCognitoCredentialsProviderHelper <AWSIdentityProvider, AWSIdentityProviderManager>
which the implementation of the identity provider manager has this method
@protocol AWSIdentityProviderManager <NSObject>
/**
* Each entry in logins represents a single login with an identity provider.
* The key is the domain of the login provider (e.g. 'graph.facebook.com') and the value is the
* OAuth/OpenId Connect token that results from an authentication with that login provider.
*/
- (AWSTask<NSDictionary<NSString *, NSString *> *> *)logins;
I think that this is our new refresh method (altought i never implemented a refresh method in the first place :P)
I was right, i just managed to implement this, if you implement the logins method of the AWSCognitoCredentialsProvider
, which will set the identityId and also return an AWSTask
with a dictionary containing [self.indentityProviderName : <THE OPEN ID RETURNED> ]
, everything works
Remember not to overload identityProviderName
(it has to be something like cognito-identity.amazon
.etc)
And to overload the identityPoolId to be the one you have setup
7 days already and no proper documentation for how to reimplement something that was broken. Considering how huge this SDK you can imagine how agonizing this can get. I wasted various hours already on this to no avail. Rolling back to pre 2.4.0 and scrutinizing every minor update on this repo.
I agree with everyone else here. Ive spent countless hours debugging and googling and reading aws documentation, until i found this thread. If you make an update like this , atleast provide documentation for something like this , custom developer identity is not a small thing to skip documenting.
Whats even more fun is googling around every freaking website to find the older version . .. . great
I want to take a little bit of time to explain the version numbering convention we use in our SDK.
The incremented first digit indicates a total overhaul of the SDK. There is almost no backward compatibility, and you need to completely rewrite your app. This happened when we jumped from 1.x.x to 2.x.x.
The second digit indicates minor breaking changes. For example, from 2.2.x to 2.3.0, we started including bitcode
. Because Xcode 6 does not support bitcode
well, we bumped the required version of Xcode from 6 to 7. From 2.3.x to 2.4.0, we dropped the support for iOS 7 and updated the credentials provider protocols (the custom login provider is one implementation of credentials provider). One exception to this rule is that we do not bump the second digit version when we make breaking changes to beta labeled components (e.g. AWSS3TransferUtility
).
We release updated API docs with the SDK update. @guillecom used them to implement the credentials provider on his own. http://docs.aws.amazon.com/AWSiOSSDK/latest/Protocols/AWSCredentialsProvider.html http://docs.aws.amazon.com/AWSiOSSDK/latest/Protocols/AWSIdentityProvider.html http://docs.aws.amazon.com/AWSiOSSDK/latest/Protocols/AWSIdentityProviderManager.html http://docs.aws.amazon.com/AWSiOSSDK/latest/Protocols/AWSCognitoCredentialsProviderHelper.html
We are still working on more detailed documentation with sample apps. They will be available shortly. If API documentation is not enough, and you need more help, please watch out for 2.x.0 releases and evaluate thoroughly before jumping on it right away since they contain some breaking changes.
We understand this is not Semantic Versioning 2.0.0 compliant, and this may be one of the reasons some people got confused. We will see if we can adopt Semantic Versioning in our SDK.
Thanks,
@yosuke-matsuda @guillecom I'm no being able to get as far as login in and getting my token and cognito ID. But once I try and do something like query a table it comes back with error:
> [Error] AWSCredentialsProvider.m line:563 | __44-[AWSCognitoCredentialsProvider credentials]_block_invoke.345 | Unable to refresh. Error is [Error Domain=com.amazonaws.AWSServiceErrorDomain Code=11 "(null)" UserInfo={Type=Sender, Message=Not authorized to perform sts:AssumeRoleWithWebIdentity, Code=AccessDenied, __text=(
> "\n ",
> "\n ",
> "\n ",
> "\n "
> )}]
> Optional("The operation couldn’t be completed. (com.amazonaws.AWSServiceErrorDomain error 11.)")
Before I never had to deal with sts:AssumeRoleWithWebIdentity ? Is this something I need to add now?
@yosuke-matsuda Might it be easier to get this to work being it on the mobile hub code example where there is a AWSMobileHubHelper that has a AWSSignInProvider.
Looking at that code though, I'm not sure how to implement the login() method in order to get the AWSIdentityManager.defaultIdentityManager().loginWithSignInProvider(signInProvider, completionHandler: {(result: AnyObject?, error: NSError?) to be called back?
Same problem here! If I want to add AWSCognitoIdentityProvider pod, it asks me to update AWScore to 2.4.0. If I update to 2.4.0 then I get this thread problem! So I'm in a loop. I can't user AWSCognitoIdentityProvider and I can't update. Please solve this problem asap and update samples! Everybody would appreciate it! Thanks
Just pushed an updated Cognito Sync Demo app to a branch. You should take a look at the implementation of DeveloperAuthenticatedIdentityProvider
. This branch uses only Developer Authenticated Identities to highlight the usage of DAI. However, you can simply provide identityProviderManager
to DeveloperAuthenticatedIdentityProvider
to add any other identity providers.
This Cognito Sync sample app seems to be a little behind of the latest AWS SDK updates, and there are many areas where it overlaps with AWS Mobile Hub generated sample apps. We will try to integrate AWSIdentityManager
from AWS Mobile Hub to this sample app as @helloniklas suggested. When it is done, we'll update the master branch. Thanks.
@yosuke-matsuda So I now get the token and the identiyID fine, however, once I try and make a dynomdb call I then get an error saying
Not authorized to perform sts:AssumeRoleWithWebIdentity, Code=AccessDenied
This does not happen when running 2.3.6 with the same dev identity providers. Not sure if there's some clash with the new identity pools somehow, as I'm not aware of this sts:AssumeRoleWithWebIdentity and why it's being denied when running 2.4.0 and not while running 2.3.6 ?
@yosuke-matsuda I did create in AmazonClientManager.swift a new function called customLogin:
func customLogin() {
let userPoolConfiguration: AWSCognitoIdentityUserPoolConfiguration = AWSCognitoIdentityUserPoolConfiguration(
clientId: "3ds8p7eog7rddXXXXXXXXXXX",
clientSecret: "cu3n1h7kb4n7j72q4XXXXXXXXXXXXXXXXXXX",
poolId: "us-east-1_onzXXXXXX")
AWSCognitoIdentityUserPool.registerCognitoIdentityUserPoolWithUserPoolConfiguration(
userPoolConfiguration,
forKey: "UserPool")
let pool = AWSCognitoIdentityUserPool(forKey: "UserPool")
self.completeLogin(["us-east-1_onzXXXXXXX" : pool.token()])
let phone: AWSCognitoIdentityUserAttributeType = AWSCognitoIdentityUserAttributeType()
phone.name = "phone_number"
phone.value = "+44434343434"
let nickname: AWSCognitoIdentityUserAttributeType = AWSCognitoIdentityUserAttributeType()
nickname.name = "nickname"
nickname.value = "Hello"
let email: AWSCognitoIdentityUserAttributeType = AWSCognitoIdentityUserAttributeType()
email.name = "email"
email.value = "email@mydomain.com"
pool.signUp("Hello", password: "Rasdfgf123456", userAttributes: [email, nickname], validationData: nil) .continueWithBlock({ (task: AWSTask!) -> AnyObject! in
if ((task.error) != nil) {
print("Error: \(task.error)")
}
if ((task.result) != nil){
print("User Created")
}
return nil
})
}
but I'm getting this error compile error:
[Error] AWSCredentialsProvider.m line:423 | 73-[AWSCognitoCredentialsProvider getCredentialsWithCognito:authenticated:]_block_invoke | GetCredentialsForIdentity failed. Error is [Error Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=9 "(null)" UserInfo={type=ResourceNotFoundException, message=Identity 'us-east-1:a2d8ee68-34aa-413d-9a09-38a57e820XXX' not found.}]
It looks like is trying to find this identityId in my Federated Identities panel, but since it doesn't exists, is shows this error. What it missing in order to have this identity Id created?
@yosuke-matsuda If I change the Trust Relationship to
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "*"
}
it does seem to work now... however, not sure what these trust thing is all about as I didn't need that under 2.3.6
@helloniklas Are you passing unauthRoleArn
or authRoleArn
to the credentials provider? For Enhanced Flow, you do not need to pass these values (See Authentication Flow for more details). If you are passing Role ARNs, can you remove them and try again?
@Stradix The error you are encountering does not seem to be related to the logins
dictionary. You can create a new thread with detailed steps to reproduce the issue. AmazonClientManager.swift
alone is not enough to reproduce the issue.
@yosuke-matsuda right, that seems to work now, missed that these were set to nil in your example.
@yosuke-matsuda However, I'm now running in to some other issues I didn't have with 2.3.6. If I first log in with DeveloeprAuthenticated ID, then logout, and try and log in with Facebook, it won't work until I completely shut the app down and login. Seems the logout doesn't really work properly. Before I could clear the logins but now with 2.4.1 I set keychain etc to nil and
AWSCognito.defaultCognito().wipe()
if let credentialsProvider = AWSServiceManager.defaultServiceManager().defaultServiceConfiguration.credentialsProvider as? AWSCognitoCredentialsProvider {
credentialsProvider.clearKeychain()
}
But this somehow doesn't work properly. Even after loging out then authenticating with Facebook, when I then try and do a request, it still tries to refresh the DeveloperAuthenticated thing.
And vice versa, if I first login Facebook, then logout, when then loging in with DeveloperAuth, it still tried to refresh the Facebook manager, although I've set the AWSCognitoCredentialsProvider to use the DeveloperAuth.
@yosuke-matsuda I also now get an error the first time the app is installed and try to login,
AWSiOSSDK v2.4.1 [Debug] AWSInfo.m line:122 | -[AWSServiceInfo initWithInfoDictionary:checkRegion:] | Couldn't read the region configuration from Info.plist for the client. Please check your `Info.plist` if you are providing the SDK configuration values through `Info.plist`.
2016-05-04 16:16:04.594 Duoo[11194:3028281] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The service configuration is `nil`. You need to configure `Info.plist` or set `defaultServiceConfiguration` before using this method.'
this causes the app to crash. It then works the second time around. Seems 2.4.1 is very flakey? Or I'm missing something in the implementation.
@helloniklas The reason why you needed to open up your trust relationship above was likely because you were passing in roles for a different identity pool. Since the pool didn't match what was in the amr, requests were getting rejected. Now that you are not passing in roles (you've set them to nil) it is using the correct roles that are associated with your pool. You should always lock down your trust relationship, otherwise anyone using Cognito Identity can assume your roles.
Without seeing what you are doing in your IdentityProviderManager, it is difficult to tell why you are still authenticating as dev auth after logging out. Do you pivot to setting the Facebook token in the logins map after logging out and is the Facebook token the only item in your logins map?
With your app crash, are you correctly setting the defaultServiceConfiguration? See Step 4 for an example.
@behrooziAWS The pool was the same, I only have one. However, passing nil seems to work. As for the crash I'm now getting on first login. I do set the things as you suggest. But, it seems when I then do a dynamoDBObjectMapper.query after getting the credentialsProvider.getIdentityId().continueWithBlock it crash bacuse the dynamoDB service thing hasn't got the right things set yet? Which is odd, didn't happen before. If I then try and login again after the crash, it works. So, it seems the defaultServiceConfiguration that I set is not being picked up by dynamoDB?
self.identityProvider = BYOIProvider()
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, unauthRoleArn: nil, authRoleArn: nil, identityProvider: self.identityProvider!)
credentialsProvider.invalidateCachedTemporaryCredentials()
let configuration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
@behrooziAWS and how to I now set the logins map? I thought logins had been deprecated?
Does your BYOIProvider only implement AWSIdentityProvider? In order to support multiple login providers, you need to initialize your AWSCognitoCredentialsProvider with a AWSIdentityProviderManager to manage the logins map and pivot between providers when you switch. The logins map in AWSIdentityProviderManager is what I am referring too. We will look into the issue you are having with object mapper not having the defaultServiceConfiguration further.
@behrooziAWS my BYOProvider() is a AWSCognitoCredentialsProviderHelper and implements
override func getIdentityId() -> AWSTask
func logout()
override func token() -> AWSTask
However, I do not necessarily need the logins to merge. I.e. if user is logged out and logs in with Facebook, it can be a new user, which is what I had working all fine under 2.3.6. Reason for this is I have loads of legacy users I migrated from Parse.
So, this whole thing seems a bit of a mystery. It's odd that the second time around, after a crash, it does have the defaultServiceConfiguration.
What would really make this easier if is someone could provide a clean sample of how to implement the equivalent of your AWSFacebookSignInProvider that is used in the generated sample app of yours. In that sample app there are no hints as to how to implement your own provider. The other CognitoSyncSample you have that was updated I find a bit messy to follow, and it's also mixed with loads of objective-C. Under 2.3.6 it was possible to get it all working fine, but now I have all sorts of issues, as this crash.
@behrooziAWS @yosuke-matsuda Also, the CognitoSyncSample doesn't seem to implement the - (AWSTask<NSDictionary<NSString,NSString> > )logins either.... I guess it's not needed if only using one provider?
It would be great to get the Cognito developer authentication example in Swift too
If I want to use developer authentication, which class do I need to extend now? AWSCognitoCredentialsProviderHelper
?
@behrooziAWS @yosuke-matsuda So I completely scrapped my previous Swift implementation and just use the CognitoSyncDemo (modified to call my lambda auth backend). It now does work fine to log in.
But, if I then logout and try and login with Facebook provider, it won't have it. I have to quit the app then login with Facebook provider and it works.
Not sure how to handle this. As in your sample you're setting the defaultServiceConfiguration in a method, but it seems you can't then change this in the same app run, to logout and in with Facebook instead, it won't pick it up. This is the method I'm referring to:
func initializeClients(logins: [NSObject : AnyObject]?) -> AWSTask? {
print("Initializing Clients...")
AWSLogger.defaultLogger().logLevel = AWSLogLevel.Verbose
let identityProvider = DeveloperAuthenticatedIdentityProvider(
regionType: Constants.COGNITO_REGIONTYPE,
identityPoolId: Constants.COGNITO_IDENTITY_POOL_ID,
providerName: Constants.DEVELOPER_AUTH_PROVIDER_NAME,
authClient: self.devAuthClient,
identityProviderManager: nil)
self.credentialsProvider = AWSCognitoCredentialsProvider(
regionType: Constants.COGNITO_REGIONTYPE,
unauthRoleArn: nil,
authRoleArn: nil,
identityProvider: identityProvider)
let configuration = AWSServiceConfiguration(region: Constants.COGNITO_REGIONTYPE, credentialsProvider: self.credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
return self.credentialsProvider?.getIdentityId()
}
If I in there add a check to see if I should use Facebook, and then use
if logins?[Constants.FB_PROVIDER] != nil {
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: Constants.CognitoIdentityPoolId, unauthRoleArn: nil, authRoleArn: nil, identityProviderManager: FaceBookIdentityManager())
let configuration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
}
It only works if I didn't first log in and out with auth client?
How can I change the service provider with out quitting the app?
The identityProviderManager(which you are currently setting to nil) should be what you use to change the login provider. Instead of attempting to swap out the credentials provider when you switch to Facebook, you should update your identityProviderManager to return the logins map containing just the Facebook key and Facebook token.
@behrooziAWS The problem I get if I do that, is that after logging out, then logging in with Facebook, it does call the identitityProviderManager I supplied, but it also keeps going into DeveloperAuthenticatedIdentityProvider getToken() then causing an error.
@behrooziAWS Problems seems to lie in your samples code call to
credentialsProvider?.getIdentityId()
As when this happens, it uses the DeveloperAuthenticatedIdentityProvider
@behrooziAWS It just seems like it's not possible to logout and have it forget what it previously was logged in with, event if the keychain is cleared, so it should be back to how it was to start with.
@helloniklas Ok, we'll look into this in more detail.
@behrooziAWS Thanks, would be helpful if the CognitoSyncSample was a bit more flexible, and easier to modify to use Facebook and Twitter as well.
@behrooziAWS What works for me now is to do an exit(0) and force the app to quit after logout from Cognito. Then I'm able to login again with a different provider. Not the most elegant solution though.
@roymckenzie Yes that is the class you use. See the CognitoSyncSample in this branch for an example.
@helloniklas We discovered one issue with the sample which may be causing the call to getIdentityId issue. This line should be changed to return [super token];
We are doing some more testing with that change and will push it once we have verified it works when we test with Facebook.
@behrooziAWS Hurray, that's done it. I've changed that line and I can now log in and out with different providers. Thanks!
@yosuke-matsuda Since the other issues have been closed/ marked as duplicate, I'll have to ask here because I don't know of a workaround for the Facebook integration. This thread seems to lean towards custom developer identity providers. I don't have a need for one.
From the changelog
logins
dictionary of AWSCognitoCredentialsProvider
is now deprecated. Use AWSIdentityProviderManager
to provide login providers' credentials. See AWSCredentialsProvider.h
and AWSIdentityProvider.h
for more details.Can you show us how you "Use AWSIdentityProviderManager to provide login providers' credentials" as described in the changelog?
Here's what I currently use, and I get the deprecation warning:
self.credentialsProvider = AWSCognitoCredentialsProvider(
regionType: Constants.COGNITO_REGIONTYPE,
identityId: nil,
accountId: nil,
identityPoolId: Constants.COGNITO_IDENTITY_POOL_ID,
unauthRoleArn: Constants.COGNITO_UNAUTH_ROLE_ARN,
authRoleArn: Constants.COGNITO_AUTH_ROLE_ARN,
logins: logins
)
PS. I don't have a custom identityProvider
in case you suggest a different constructor that requires one.
Probably, you should use - initWithRegionType:identityPoolId:identityProviderManager: instead of the deprecated one. You need to implement AWSIdentityProviderManager
to supply the logins
dictionary to the credentials provider whenever it needs one. Please note that this dictionary needs to contain valid tokens. See AWSCredentialsProvider.h
and AWSIdentityProvider.h
for more details.
@yosuke-matsuda
Thanks, the swift code following worked for me:
class CustomIdentityProvider: NSObject, AWSIdentityProviderManager {
var tokens : [NSString : NSString]?
init(tokens: [NSString : NSString]) {
self.tokens = tokens
}
@objc func logins() -> AWSTask {
return AWSTask(result: tokens)
}
}
let customProviderManager = CustomIdentityProvider(tokens: logins!)
self.credentialsProvider = AWSCognitoCredentialsProvider(
regionType: Constants.COGNITO_REGIONTYPE,
identityPoolId: Constants.COGNITO_IDENTITY_POOL_ID,
identityProviderManager: customProviderManager
)
@simoami
Your implementation should work as your previous implementation. However, please remember that when the token from Facebook expires, the AWS SDK starts returning authentication errors.
- logins
on AWSIdentityProviderManager
is designed to return the logins
dictionary asynchronously. We recommend the following approach when implementing - logins
.
nil
and hasn't been expired, return the logins
with the cached token.logins
, then cache it and return it.AWSTask
so that the error is correctly propagated.@yosuke-matsuda It would be very helpful if you could add Facebook login to your Cognito sample code.
So I spent ages getting a custom login provider to work. I have a class BYOIProvider extending AWSAbstractCognitoIdentityProvider based on some AWS sample. This was all working fine. However, upgrading to 2.4.0 the AWSAbstractCognitoIdentityProvider is no longer available? Do I have to rewrite this code now?