Identity Sever 4 Persisted Grants not being used - asp.net-identity-2

I've implemented IPersistedGrantStore, and defined a Client that has properties RequireConsent and AllowRememberConsent set to true. I've also removed offline access scope from that client as I've read somewhere that Consent is always forced if offline access scope is requested, as per OAuth specification.
When I go to the login screen for the first time, I'm presented with consent view, click allow and remember my decision, I can see the record in DB table PersistedGrants being added with type user_consent. Next time I try to login, that record is fetched from database by my implementation of IPersistedGrantStore, but the consent view is still presented. If I then click allow again, DB throws an exception because IS4 is trying to insert another PersistedGrant record with the same key.
Did I overlook certain setting that would make it behave as expected?
PS. I've implemented all major stores and everything is kept in SQL Server db, not using any of those InMemory stores.

After substantial amount of debugging, here's what the problem was:
_ScopeListItem.cshtml from 6_AspNetIdentity sample, has this section of code
#if (Model.Required)
{
input type="hidden" name="ScopesConsented" value="#Model.Name" />
}
This is evidently rendered only if the scope is marked as required. Those scopes that are marked as Required are only ones that get posted to controller action.
In my case I had a Client requesting OpenId and Profile as standard scopes, and also three scopes defined by my ApiResource. Admittedly I didn't mark the Api scopes as required, but the problem was also that the Profile scope wasn't required by default.
So when saving the Consent, the Data property didn't contain Profile scope, and there was a mismatch of requested and consented scopes on all following login attempts, which triggered the Consent process.

Related

Is there a way to get a second user to authorize an action without the logged in user seeing their details in the request header?

A strange situation that I am unable to find other people having to deal with. We are using Microsoft AspNetCore.Identity to handle our authentication. Everything is working fine.
The problem is that for a user to perform certain actions, they MUST get another user to 'sign' that action. This act of signing of course requires that other user to use their user name and password to sign the action.
The issue with this is that the other user's details are readily visible in the request payload. So if I am sneaky, I can open the developer tools in my browser (and hide it), then ask my admin to come and sign my action, and when they have gone i can go to the network tab and see their username and login in plain text!
Of course this is all over https but still, we can't allow one user to see another's sensitive information.
How are we to manage to allow a second userB to 'sign' an action for userA while in user A's active session, while removing the capacity for userA to steal userB's credentials??? Any ideas? (Front end is angular.js)
I imagine it's a big rework, but instead of having the "admin" sign the request on the user's machine, the admin could receive a "user A requires this action to be signed, proceed? [ok] [cancel]" on their account, the action would be stored in the database (perhaps temporarily?) & then all of the sensitive information is kept within each user's session with no cross over.
Then the authentication of who is permitted to approve actions can be handled in the backend via standard identity methods.
The user's "Please wait while an admin signs this action" modal (assumption) could then poll an API to determine the status of the action and then proceed once accepted.
I second #justcompile's answer if you need an authorised and authenticated user to sign/confirm the action, more work but the only secure way.
If you just need a second pair of eyes to confirm you could message a private group or slack channel that only "authorised" people have access to with a one-time URL containing a token (that maybe expires after a period of time too).
Assuming admins only access that channel they can follow the link, the app can validate the token and confirm the action.
Saves a second (admin) user logging in on their own machine and the need to build a workflow and UI etc, but again exposes you to risk if nefarious types get access to the channel or the links sent to it.
Depends on your appetite for risk I guess.
another user performs signing action on your local system? and you are sly?
there is no way to protect their password.
use two factor authentication.
The way this would normally be handled is for the user to request an action. This (unsigned) action-request is recorded in the database. The admin user is able to see this unsigned request in their account, and make an (authenticated) request to sign it. The user would be able to see the status of their request, and whether it has been signed yet.

Keycloak: Role based client log-in access restriction for users

I am trying to achieve fairly simple usecase of role based client application (VueJS multi-page applications) control using the keycloak.
As shown in image, I have three different roles and three different clients in single realm.
The arrow in the image represents which role can access which client.
So my main objectives are,
User with role Viewer should only be able to log-in to the Viewer Application. If the same user tries to access the Operator Application or Admin application then keycloak should simply deny this user from doing so.
The same rules should follow for users with Admin and Operator role. Users of Admin role should be able to log-in to any of these application by keycloak.
To achieve this usecase I tried following ways,
First by appropriate role mapping to users and role creation in the clients. In this case, I create realm level roles and then client level roles, then assigned appropriate roles to the users created in the user section.
Enabling the Authorization. In the policies, I removed default policy that grant all users access to the client. And create a User policy and Client policy to restrict the access to client application
Also tried with Group based authorization policy. In this case, I created a group with client role and then assigned user to these groups. And enabled them from the Authorization group policy.
But, unfortunately none of this works. Meaning my user with Viewer role can log-in to my admin application. Which is just strange.
You can do this without extensions.
Copy the desired flow (e.g. the browser flow)
Create a new sub flow (e.g. for the browser forms) and call it Access By Role and select generic as type.
For the new sub flow ensure that CONDITIONAL is selected in the flow overview.
For the new sub flow add execution Condition - User Role, make it REQUIRED and configure it:
alias: admin-role-missing
role: admin (or whatever your role is)
negate: true
Add another execution: Deny Access and make it REQUIRED as well.
The final result should look similar to this:
This will deny access if the condition "admin-role-missing" is true.
You an also learn more from the docs: explicitly-deny-allow-access-in-conditional-flows
Also, don't forget to go to your client and select the flow in the authentication overrides.
The solution proposed by #Stuck is a great start, but it has a significant flaw: When the user has already authenticated, e.g. via the standard flow of another client that did not require the role, the password form flow will never be triggered. Consequently, the user will be logged in via the cookie flow without ever checking for the role.
In other words: If there are other clients (such as the account console) that do not require the role, anyone can bypass the role check.
To fix this there needs to be an additional flow layer that includes all authentication executions, that is followed by the authorization step (no matter what authentication flow was used). The final result will look like this:
I managed almost the same problem using KeyCloak extension SPI. After the deployment you will have additional configurable "execution" in authentication flows available, named "Validate User Role".
The auth flow then look's like :
This execution must be placed after the "Username Password Form" (or other form which authenticates user) or the authentication will fail.
The source code is here :
https://github.com/ValentinChirikov/kc_user_role_validate_extension
Finally handled this at the application level as it wasn't working from keycloak end.
After the login, check for the keycloak object, inspecting on the same we can find some of the useful properties set during the configuration mentioned in the question above. The overall code looks like below,
let appName = 'your_app';
keycloak.init({ onLoad: 'login-required' }).success(function () {
// Confirm the role & authentication of the user
if (keycloak.authenticated && keycloak.tokenParsed.resource_access &&
keycloak.tokenParsed.resource_access.hasOwnProperty(appName)) {
// Continue with the app execution...
} else {
// Logout user
keycloak.logout();
}
}).error(function () {
keycloak.logout();
});
This way I managed to route unauthorized user out of the application.
The solution isn't what's required in the question asked, but it works. Although I think this should be handled at the keycloak level itself.
For anyone looking to do this in Keycloak version 20, see the screenshot. This is based on answer by #heilerich but for version 20.
NOTE: Create a new flow instead of duplicating an existing flow as it will not work.

Will the openid scope "https://www.googleapis.com/auth/plus.me" be affected by the Google+ shutdown?

I would like to know if the following scope URI would be affected by the Google+ shutdown or not.
https://www.googleapis.com/auth/plus.me
This scope is named "openid" in the "OAuth consent screen" tab of Google API Console and has "plus.me" in the URL.
The openid scope is default setting.
But the following URL says "only projects directly requesting the 'plus.me' scope are affected".
https://developers.google.com/+/api-shutdown
It confuses me...
Is the above scope URI affected by the Google+ shutdown?
Also I would like to confirm each of the following scopes and endpoints will whether be affected or not just in case because I'm using them on my project.
scopes
https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/userinfo.email
endpoints:
https://accounts.google.com/o/oauth2/auth
https://www.googleapis.com/oauth2/v3/token
Will the above scopes and endpoints be affected?
Thanks
I would like to know if the following scope URI would be affected by the Google+ shutdown or not.
https://www.googleapis.com/auth/plus.me
Note: This is not a uri it is a scope. The scope is being shutdown. You will not be able to use this scope when authenticating users to Google.
What are scopes
Different pieces of user information are often stored across a number of online resources. Users may upload and store photos with a service like Flickr, keep digital files on Dropbox, and store contacts and events in Google Calendar or on Facebook.
Often, new applications will want to make use of the information that has already been created in an online resource. To do so, the application must ask for authorization to access this information on a user's behalf. Scopes define the specific actions applications can be allowed to do on a user's behalf.
Shutdown what?
The documentation for the API-shutdown is not very good and can be a little confusing.
Beginning March 7, all OAuth token requests with scopes starting with "plus." (i.e. "plus.me", "plus.login", "plus.profile.emails.read", etc) will fail upon request, and may start to intermittently fail as early as February 15, 2019.
This being any scope starting with the word plus. If we check Google scopes This gives us the following.
So yes https://www.googleapis.com/auth/plus.me is being shut down the others you have listed are not.

Obtaining Instagram Access Token

We have a client who has a simple Instagram feature on the site to pull photos by a certain tag. They just noticed it isn't working. Getting an error - invalid access token. I guess since the 1st because of the updates. We didn't used to need an access token since we're not doing anything with users - just tags.
Now it looks like we need one and the documentation makes zero sense on how to obtain one. And it seems like they're not accepting most apps. The app is in sandbox mode too. So I'm assuming it's because it got switched to that? Got no notification of this happening.
The first step in documentation to get an access token is "Direct the user to our authorization url." What does that even mean? There's not a link provided or anything. It also says "Company Name, Contact Email and Privacy Policy URL are required to start a submission." Our app doesn't have a privacy policy... it's just a simple tag feed. I don't understand why everything is so complex to have a simple tag feed.
Is there a wait time to get the app approved..if it gets approved... Do I have to have it approved before getting an access token? This isn't outlined anywhere.
You got it right. As of June 2016 any Instagram API calls require an access token.
Getting an access token is described in the documentation. App approval is not required.
There are two ways to get one: server-side or client-side. The second option (called implicit authentication) can only be used when implicit OAuth is enabled in the client settings (Manage Clients > Edit Client > Security > Disable implicit OAuth). It is disabled by default.
In either case you need to redirect the user to the authorization URL to obtain an access token.
The URL for explicit mode (server side) is:
https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=code
The URL for implicit mode (client side) is:
https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=token
After this you will be redirected to the REDIRECT-URI, which will be passed an argument. For explicit mode this will be a query string with a code, while for implicit mode you will get the access token directly as a hash:
http://your-redirect-uri?code=CODE
http://your-redirect-uri#access_token=ACCESS-TOKEN
For implicit mode you can then get the access token from the window.location.hash in Javascript.
For explicit mode, however, you need to further process the code to obtain the access token. You can read how this can be done in the API Documentation. I'm not going to take this any further here.
The problem is that every user who wants to see your feed needs to login to Instagram (and have an account) in order to view it. In your case this might not be desired. However, there are a few options to get around this (rather annoying) problem:
You can reuse your own (already obtained) access token(s) to display the Instagram feed for every user. You will need to be aware of rate limits for each token. For sandboxed apps this is 500 API calls / hour, while live mode allows 5000 API calls / hour. [source] You could store tokens in a table and use them in a round-robin manner, to allow more API calls. This involves manually obtaining a bunch of tokens which your application can use (the more the better). This might not be the ideal solution considering Instagram doesn't warrant access tokens to have an unlimited lifetime.
You can retreive JSON data without authentication by appending /media/ to a user page URL, as described in this post. No tokens or client IDs are required for this to work. However, this only works for users, not for tags. Besides, Instagram doesn't document this feature so it is not garanteed to work in the future.
You can use an aggregator like Juicer or Dialogfeed instead which will handle access tokens for you. This is usually not free of charge.
I'm also in the process of making an Instagram feed for my website, and this is what I concluded from my research. Please bare with any errors I made.
Edit: Here are some more limitations for sandbox apps.
In sandbox mode you can only access data from sandbox users (thus users who received a sandbox invite). This means that:
Media retreived by user, e.g. /users/{user-id}/media/recent, will return an empty response if the user is not any of the sandbox users.
Media retreived by tag, e.g. /tags/{tag-name}/media/recent, will only contain tagged media belonging to sandbox users.
Thus, for a tag feed to work, it needs to be live (reviewed and approved). If you don't want to do this, the only alternative is to use an aggregator as I mentioned above.

Issues and clarification regarding O365 APIs

I have been working with the O365 APIs and found some weaknesses. I understand we are in preview, I just want to confirm the following, thanks.
There is no expiration information returned with the AuthenticationInfo object. It seems the suggested pattern is to get an AuthenticationInfo object before each call.
The SharePointClient class only supports files, not lists or other resources at this point.
The AuthenticationInfo class cannot be used to secure an entire web application. Instead, each application must authenticate users as appropriate and then use AuthenticationInfo to make subsequent calls to O365.
As an interesting side note, I tried to combine MVC5 "Organizational Accounts" authentication with the AuthenticationInfo class and the application made endless round trips to Azure AD without ever returning a token. Is there some conflict between MVC5 Organizational Account authentication and AuthenticationInfo behavior?
On the AuthenticationInfo object expiration - it expires when the refresh token does, which should be a least two weeks. The AuthenticationInfo.GetAccessToken delegate implementation keeps track of the issuance time and validity of access tokens and makes sure to refresh them automatically when they are nearing expiration.
Re: SharePointClient and Lists, etc.
You are entirely right. This was a scoping decision for this release, but we will be adding support for lists in near future.
There is not supposed to be any conflict between "Organizational Accounts" and AuthenticationInfo.
I just tried using the combo and it worked fine from project creation (using single organization and read-write access to data) through F5. I had to make sure the project had a unique name because otherwise, the web project was picking up a redirect URL from an old registration. That was unrelated to Office 365 APIs, though.

Resources