I am unable to revoke application access by a user via either a password reset or by explicitly clearing app keys in user management. The latter method gives a reply indicating that access has been revoked, but when the user hits the tool, they are not re-prompted to approve access to their information.
There are number of possibilities here:
It's possible that there is latency between the declared revocation of keys and the cleanup task that goes through the database and actually cleans them up; I believe that at one point, such a latency existed, was identified, and fixed through service packs and subsequent releases. Accordingly, you may address this issue by ensuring that your back-end service is up-to-date with its available service packs.
It's possible that what's being revoked is the keys, and the necessity to authenticate to rebuild keys, but not the confirmation step that would appear to the user asking for access permission (assuming the user once authenticated, and checked the "don't prompt me to ask for permission again") dialog.
Can you confirm if the request for user tokens by the client application actually does get back tokens? Or is it just that the authentication step happens with no notice of client confirmation to access?
Note that the re-authentication might appear to happen silently; if the client application's request for user tokens happens through a user's browser context where the back-end service can determine that the user is already logged in to the LMS, then the request for tokens could succeed automatically:
The user is assumed to have already authenticated in order to have an active web session, so there's no need to re-gather a username/password (or whatever user auth step the LMS uses) to re-confirm identity.
The user may already have confirmed access for the application and dismissed the confirmation step with "don't ask me again". If the user has confirmed access with "don't ask me again" this choice will get remembered, even if the user tokens get expired due to password change or access revocation by an admin.
If you explicitly log a user out of their LMS session, and then test the client app, this should indicate to you visibly whether the re-authentication step is actually taking place (the user's browser will then get directed to the login process for the back-end service).
Note that, although a user password change or access revocation by an admin can remove the recorded user Id/Key pair associated with an application, it does not remove the record of the confirmation form having been dismissed with "don't ask again". Currently our system does not expose a way to reset that confirmation state.
If after considering these points you feel you still have an issue, I would encourage you to open a support incident through your organization's approved support contact, or your account or partner manager. Desire2Learn takes security related reports quite seriously, and if you've uncovered an issue that hasn't yet been addressed, I would encourage you to report it as a defect.
Related
I am in the process to design a login for a new app that will be associated with a domain, i.e. be the counterpart to an SPA.
Obviously I want to use
iOS 11 Password Autofill, and
Shared Web Credentials
I have read the documentation on autofill as well as watched the WWDC video about it. Also, I checked the article on Shared Web credentials, which I think is older than the new, reworked autofill. Said article recommends:
Do not use the shared web credentials as your primary storage for secure user credentials. Instead, save the user’s credentials in the keychain, and only use the shared web credentials when you can’t find the login credentials in the keychain.
This strikes me a little odd, because it
- Means I have to cover more possible inconsistencies, i.e. synchronize the keychain somehow wit the shared web credentials (what if I have credentials in the keychain as well as the shared web credentials, but they're different?)
- Potentially leaves "garbage" behind in the keychain if my user user uninstalls my app (naturally I hope they won't ever do this, but let's be realistic, some will)
Especially the last point had always bothered me in the past (before shared web credentials and autofill were a thing, or when my app doesn't have an associated domain). Unlike on macOS, the iOS Accounts & Passwords feature (in the Settings app) doesn't list ALL passwords, but only the ones used by Safari (i.e. the shared web credentials), correct? Keychain Access on macOS instead offers a means to view and manage all credentials, even those that aren't synchronized over iCloud.
I understand why the same is not offered on iOS, but it also means that for those passwords that my app saves (locally) to "its" keychain "part" can only be managed if I offer a UI for this in my app. And if the user uninstalls the app before using this, the item will stay in the keychain, at least it was that way when I tried it a couple of years ago.
My main question now is, wouldn't it be easier to disregard the article's advice and only rely on the shared web credentials for password storage? That's the part they can edit in Settings (if ever need be) and also it will reflect any password changes done on the website. I would design my app like this then:
First launch: App starts on the Login screen and offers the username/password via Autofill
User logs in: App saves a simple flag in the shared user defaults indicating the user is logged in.
App gets relaunched, e.g. after a device reboot: The app skips the login screen due to the flag and gets the password and user name from the shared web credentials (assuming the user previously granted it permission, of course)
User explicitly logs out: The app deletes the flag, basically setting everything back to first launch
User deletes the username and password from the shared web credentials (e.g. in the Settings app or with Keychain Access on macOS): The app falls back to the login screen as soon as it detects this (e.g. when attempting a remote request, or after relaunch), regardless of the flag. I think this matches the user intention best (if you delete a password you don't want some apps to hold onto it until you log them out)
This setup would avoid any issues with different items in the keychain and shared web storage and it would immediately propagate updates done in the webpage to the app as well (which is what I'd intent for my app anyways). Is there anything that would keep this app flow from working?
(Note: I asked the same question on the apple developer forums, so if you see that as well don't be confused. I will update any potential answers from there to here and vice versa.)
Edit to address #Aaron's answer:
Thank you so much for the info. Your answer helped me realize I misunderstood something about shared web credentials: I assumed that for an app with associated domain, you can access the credentials without user interaction (after perhaps an initial authorization). Like you can set the checkbox on macOS when an application requests credentials. I now realize this is wrong and on iOS you would always have to verify with the user, thanks.
For completeness sake, I still want to point out some of the other things you said:
You are right, we will eventually use token based authentication, so I will save that in the keychain (probably in addition to the password, see below). I just tried to keep the question simple enough at first.
Our app is like an email client where you update new incoming "mail". The mentioned "login flag" in something like the user defaults would thus just indicate whether the app should behave as if subscribed to an inbox or not. Like in Mail, you wouldn't expect to have to login even after relaunch.
For this reason I will probably eventually save the user's password in the (local) keychain along with a token. If the token expires, I can request a new one without user interaction, that's important in our general site and app design. Only if that request fails I would use the shared web credentials (updating my local copy of the creds in the process).
For what it's worth, the last point you mentioned is probably debatable. On macOS, for example (where you can edit the entire keychain, not just Safari passwords) de facto logs you out of an app. Mail, again, as an example. If the keychain item for an inbox is gone, Mail re-asks that the next time it is launched and tries to access the content (effectively a "kind of" login in a way).
Again, thank you a lot for answering, now I can close an open todo. :) Also thanks to #HamZa for giving out a bounty!
Considering this advice:
Do not use the shared web credentials as your primary storage for secure user credentials. Instead, save the user’s credentials in the keychain, and only use the shared web credentials when you can’t find the login credentials in the keychain.
The main issue here is that the shared web credentials process is a little clunky — it requires user interaction and takes time to resolve the credentials. So if the user has already authenticated with your app you want to avoid showing them the login page at all. You can do this by storing credentials in your app's keychain where you can access them immediately without a network connection or user permission.
This doesn't mean you need to store the user's password in the keychain. Typically you would store something like an OAuth access token in the keychain. The presence of this token means the user is authenticated - and if an API endpoint rejects your token then you can take them back to the login page.
This suggestion:
User logs in: App saves a simple flag in the shared user defaults indicating the user is logged in.
is possibly insecure depending on what you're hiding behind the login page, but typically any content belonging to the user should require a valid token to access, not just a bool in the user defaults.
I think this matches the user intention best (if you delete a password you don't want some apps to hold onto it until you log them out)
I disagree with this; I would not expect an iOS app to log out because I deleted a password from my Safari keychain.
I cant find any help around on this topic because I am being told how to implement it rather than how it actually works.
All I know is two-factor authentication is authenticating users through an email and a phone number.
Here are my set of questions :
Does it authenticate users by verifying their email and phone number at the time of registration?
Does it authenticate users by verifying their email and phone number on every login?
Why is it that every user can set two-factor authentication enabled or disabled for their account? Isn't this an admin thing which should not be decided by the user?
I'll see if I can help clarify for you.
It works as an extra level of security. Traditionally you would have a username/email and password to get into a site. If the password is compromised then so is the account. Adding a phone number to your account will mean that only someone with access to that phone can get past the extra level of security and access your data.
When the user logs in with another 'step' is added before they get through. A token (usually a number with a short expiry - i.e. seconds) is tied to the user logging in and sent to their phone. They fill in the form and submit. The device the user is logging in with (laptop/phone/desktop browser) can then be tied to their account (see point 2 below).
This can be the case but if you take Google as an example you can select to 'Trust' the device logging in for 30 days. This ties the device to a trusted list (perhaps stored in a database for instance) for a set amount of time before asking at the point of login again.
Common practice is that it is the user's choice as to whether they have this extra level of security. They may not have access to a phone...what happens then? They may like the convenience of just using a username/email and strong password....it doesn't mean to say you can't force it by design in your system though.
I am creating an application using Appcelerator wherein the user needs to enter the username and password to login. Once logged in, the user can enable TouchID for authentication. After logging out, the user can use the TouchID for authentication and use the application.
My flow is that once the username and password is provided, I store those two information in Keychain using the following module iOS Keychain Module. Then I use ti.touchid to authenticate the fingerprint, if success, then I retrieve the username and password from keychain and then send it over HTTPS web service call and login the user to the application.
My query is that, whether this is an acceptable approach.
I am not an iOS developer nor does any ti or keychain terms mean anything to me at all. That's for a start and to reduce the number of down votes i might get.
In terns of security, I would suggest that you imagine obtaining that particular user's phone where you know you have some authentication credentials stored. Let's say I am a user of your app, already logged-in and have my credentials saved somewhere on my device, and you obtain this phone by stealing it from me.
Now, will you be able to access my account in anyway? Will a hacker with access to the physical phone be able to retrieve any information stored in your Keychain storage?
If so, If you can think of anyway to do so, then your approach is not valid.
I understand you want to save users sometime by making sure they can login with just their fingerprint, which is a valid reason to think of such an approach, but you will have to think everything in terms of reverse engineering.
Additional recommendations would be using an on-the-fly hash to store information in the Keychain and making sure to check that before restoring the same. For example, user credentials saved on "home wifi" can be verified with your fingerprint only "at home" on the same wifi network where the same will be invalid on a different network.
i.e)
(keychainItem.x = y) is TRUE ONLY IF (something else)
where this (something else) is something that will prevent hackers from accessing the Keychain even if they have access to the device itself.
I do this myself when programming web applications with stored cookies. I for example use a stored cookie ONLY IF it is being accessed from the same IP it was saved from. Anytime that IP address changes, user will have to re-authenticate even if the cookie values are correct.
Hope this helps.
I'm working on a cloud-storage API, authorized via OAuth. Users of third-party applications can permit said application to access their files/data via our RESTful API.
Currently, we are limiting a third-party app access to a users account once. E.g., the Access Token table has a UNIQUE on the consumer column and the user column. This makes sense at first glance, as the user should never be sent to our service to authorize a third-party application twice, since the third-party would already know their user is already tied to our service and wouldn't need to be re-authorized.
However, what if this user has two accounts on the third-party app, and they want said app to connect to their single account on our service twice? This seems likely, given the prevalence of multiple accounts on services such as Reddit.
Here are the possible solutions I've come up with so far, none of them being perfect:
Display an error during the second auth request: This seems like a frustrating experience for the user, a "cop out" of sorts.
Delete the previous token: This would likely annoy the user, as their previous accounts stop working. Even if we display a warning, it would likely be hard to explain what exactly is happening.
Return the same access token as the first request: Each time the access is requested, a set of permissions are also passed along. The permissions for the second request could be different than the permissions for the first request. Also, not sure if this will violate the OAuth spec, as the secondly generated Request Token isn't tied to the Access Token properly.
Allow two to be generated: This would be confusing, as when the user visits their screen full of authorized applications to revoke one, they don't know which authorization is tied to which third-party account. We could ask for an optional third-party username parameter when the Request Token is generated to identify the different auth's (we currently ask for a non-OAuth-standard permission parameter already). But, this seems like it wouldn't be used by 99% of developers and could make application development more confusing.
What is the best way to handle this situation? Is there a standardized practice for handling this use-case?
I think your last case is the right way to go - Allow two to be generated
When the user visits his screen full of authorized application, it's not necessary to show him one and the same Application twice - you just have to delete the tokens associated with the app if the user revokes application access. That is, all his authorizations to the app with all tokens will go away with the revoke, which is fine.
I'm currently implementing an Oauth consumer service which is going to use Soundcloud as an Oauth service provider as well. But I'm having the following issue with it: Taking Facebook or Twitter example, you go there, you sign in, you fill up the permission form, and you are redirected back to your app. If you go there a second time, and given you are already sign in, you basically skip all steps and are redirected back instantly. That means, Facebook recognized that you already gave permission to that 3rd party service, so it doesn't ask your permission constantly.
And that's what's happening when I use Soundcloud. Basically everytime I redirected the user to the Soundcloud Oauth connect endpoint, the permission form always shows up, even though I already gave permission to that 3rd party service previously. I'm forced to press "connect" every single time, which is a drag from the user perspective (how many times can you give permission to the same entity). My question is: is there a parameter I can use to make soundcloud recognize/validate the previous permission from the user account to that specific 3rd party service? Or is this Soundcloud Oauth design implementation and we have to live with it?
Edit:
Maybe this wasn't clear, but each time I press "connect" in soundcloud, a new access token is being generated and delivered. Since my app uses this access token to identify its users, it doesn't work very well for me that the access token is getting updated everytime I want to log in, making me effectively "sign up" everytime. To sum it up, I want to get the previously attributed token to my account, so I can look up in my database, identify it and log him in.
I'm also looking for a solution which doesn't involve storing state in the client that might get cleaned up.
What you can do is store the user's oauth token in local storage and reuse it in future sessions. That's what happens on soundcloud.com.
A longer explanation:
When you use the Connect flow, the user is authenticated by SoundCloud (either by using username/password, Facebook Connect, or an already-existing session on soundcloud.com), and then when it is successful, your app is given an oauth token for that user. This is passed to the callback page which is registered for your app.
That token is the only piece of information needed to have the user be "logged in". Unless the token expires (by time, or by the user manually revoking it), then you can reuse that in future sessions.
I think I'm a bit confused about your application's design: where and how is the oauth token being used? I think that instead of using the token as an identifier, perhaps the user's permalink might be better? If you have the oauth token, you can find out the permalink by querying api.soundcloud.com/me.