How to implement user “auto-approval” with Forgerock OpenAM and OAuth2

Tagged: ,

This topic has 22 replies, 8 voices, and was last updated 3 years, 4 months ago by Andy Cory.

  • Author
    Posts
  • #8259
     Miguel F
    Participant

    0
    down vote
    favorite
    I want to use OpenAM as IAM platform. On the other hand I want to protect and provide fine-grained access to a layer of REST services using OAuth2 with OpenAM playing the role of OAuth2 Server / Provider.

    This is working for me already, however in this case I would like the screen for the user to confirm access not to appear. The reason being is that in this case I’m not really using OAuth2 for delegation. At the end of the day I want my REST services layer to be protected. The user should not even realize that we are using OAuth2 for this purpose.

    Is there an “auto-approval” feature (similar to the existing in Spring OAuth2 framework) to explicitly avoid the approval screen being shown to the user and approve automatically instead? I had a look at the OpenAM documentation but I could not find anything..

    Any help will be appreciated. Thanks!

    #8262
     Bill Nelson
    Participant

    You can bypass the consent page by populating a saved consent attribute with a particular value.

    The OAuth2 Provider service specifies a user configurable “Saved Consent Attribute Name” where you can specify the saved consent attribute (I typically extend the schema to use something like “exampleSavedConsent”). Then simply pre-populate that attribute with the value of the client_id and the scope and consent is granted without user involvement.

    We found some issues with the format of the value of the saved consent attribute where you had to specify a space at the end of the attribute value. This means that your data will most likely appear in a base64encoded format in your LDAP server.

    #8267
     Andrew Potter
    Participant

    You could also use a different access token Grant Flow.
    I assume you’re using the Authorization Grant, which by definition in the spec, requires that the AS seeks consent from the user. (As Bill says, you can potentially pre-fill this consent).
    See the description of Step (B) below Figure 3: https://tools.ietf.org/html/rfc6749#section-4.1

    If you use the Resource Owner grant then consent is not required to be sought.
    https://tools.ietf.org/html/rfc6749#section-4.3
    https://backstage.forgerock.com/#!/docs/openam/13/admin-guide#oauth2-ropc
    Note that the client is calling the access_token REST endpoint with the credentials, rather than re-directing to the OpenAM login page. This means that the client must have a way of collecting the credentials. Also, from the spec, the grant type is “suitable in cases where the resource owner has a trust relationship with the client”.

    #8271
     Bill Nelson
    Participant

    Good point, Andrew. Programmatic flows such as the Resource Owner grant flow do not require consent. I was trying to stay within what I interpreted as the current behavior of the application. But you are correct, if the application can be modified to implement a different grant flow, then this would be a better approach.

    The pre-authorized consent is sort of (hate to say the word, but here goes) a hack; but a useful one nonetheless. I personally only implement this methodology when all parties (AS, Client, RS, RO) are within the same organization (i.e. in an intranet scenario). I’m not a fan of pre-authorizing consent that the user has not provided themselves when the different entities cross boundaries. That just seems icky (and yes, that is a technical word). ;-)

    #8273
     Miguel F
    Participant

    This reply has been reported for inappropriate content.

    Bill, Andrew,

    thanks so much for your responses.

    Yes, the flow / grant type I’m implementing is Authorization Code which is mostly indicated for clients that are web applications (besides is the safer in this case taking into account that they are confidential clients – can keep secret).
    In particular in this scenario I’m protecting a REST API that is accessed by a Single Page Application (HTLM5).
    Instead of the SPA handling the tokens directly with the Authorization Sever, I have an API Gateway (implemented with Spring Cloud Suite + Spring OAuth2) that is able to obtain the tokens and relay them downstream (to the REST API).
    So, yes, in this case Authorization Server, Resource Server (REST API) and client (API Gateway) belong to the same organization.
    Besides I could have other authentication mechanisms for instance for intranet users (integrating Windows Desktop Login which OpenAM supports). OAuth2 spec describes an authorization flow, but they don’t specify how the authentication must be performed so as long as the user has authenticated with OpenAM (has a iPlanetDirectoryPro cookie, for instance) the authentication mechanism doesn’t matter.

    So, basically in the end what I want to protect are the REST services that a Single Page Aplication UI will access. In this case it would make no sense to ask the user: “Do you grant access to your SPA to access the services that the own SPA UI need to use?”.
    At the eyes of the user the application is like any other SPA (HTML5) accessing its own REST services inside the same organization. The user doesn’t need to realize about OAuth2 (and probably has never heard of! :-) ).

    This scenario I described is becoming more and more common to protect REST APIs. It is common to have different sort of clients that don’t handle OAuth2 tokens directly and an API Gateway (with Spring Cloud NetflixOSS we have Zuul Proxy, for instance). Similar approach to have OpenIG as API gateway to obtain and relay OAuth2 tokens.

    Exactly this I had implemented with Spring Cloud + Spring OAuth2 with ZuulProxy as gateway with a simple authorization server implemented with Spring stack (which allows to register a client specifying “auto-approval”!). This was working fine and I just wanted to replace the spring oauth2 server by OpenAM. As both they follow the OAuth2 spec this worked fine, however I can’t implement “auto-approval” with OpenAM.

    Regarding the solutions you provided I agree with you.. they seem more like workarounds (not to say hac..”). From my point of view it would be desirable that OpenAM provided with a check “auto-approval” in the setup for this sort of scenarios.

    Thanks for your help

    #8275
     Bill Nelson
    Participant

    I’m not sure that the “check box” to tell OpenAM to auto approve is possible as you still need to define what it is that is being auto-approved and for which client the auto approval is being applied. The consent is saved in the user’s profile so either way you need to define the name of the attribute where to store/read the consent. This is not part of a directory server’s typical schema so you would need to extend that schema to accommodate and then decide what to store in the attribute value – and that will be based on the scope you are allowing in the consent. So again, I don’t see how you could check a checkbox and make this all work out. Now a wizard, maybe…..

    Note: One could argue that OpenAM should simply add new extended attribute to the user’s profile in which to store the saved consent (since it already has extended profile attributes), but that assumes that OpenAM is managing those users, itself, and that is a bad choice/assumption (we can talk about the pros/cons of OpenAM user management in another thread).

    #8276
     Miguel F
    Participant

    Hi Bill,

    Yes, exactly, the “auto-approval” indicator would be associated to the client registration. It can’t be generic.

    This is an example how to set “auto-approval” on client registration with Spring in a programatic way I used for testing purposes and they are directly stored in a in-memory database. This way of registering clients for my point of view is more for evaluation / showcases purposes.. You could do the same with a database script to add the clients directly to the data model instead. Obviously OpenAM supports client registration from the console (and client auto-registration, at least for OpenId) and much more features.
    But just to see in which context the “auto-approval” flag would be set is a good example (per client registration when you specify scopes, supported grant types for this client, client id and secret and so on).

    clients.jdbc(dataSource)
    .passwordEncoder(passwordEncoder)
    .withClient(“client”)
    .authorizedGrantTypes(“authorization_code”,”refresh_token”)
    .authorities(“ROLE_CLIENT”)
    .scopes(“read”)
    .secret(“secret”)
    .autoApprove(true)
    .accessTokenValiditySeconds(200);

    So yes, I agree with you the flag / indicator can’t be generic.
    Well this is an idea.. is how Spring supports it and it works perfectly.

    Thanks again!

    #8279
     Bill Nelson
    Participant

    Thank you for providing the Spring snippet, Miguel. Good stuff.

    Let me know if you have any problems getting this to work with OpenAM.

    • This reply was modified 6 years, 6 months ago by Bill Nelson.
    #8283
     Miguel F
    Participant

    Thanks Bill.

    Yes, the snippet is just to see an example of implementation, an idea.
    In OpenAM might be different as the data model is different – at least it will be necessary to map the field where the consent is stored per every user.
    But regarding the moment where you can set this up in OpenAM (specify that for that client you want to implement auto-approval) I guess it could be where you register each OAuth2 Client as agent (OAuth 2.0/OpenID Connect Client -> Agents).

    I will keep you posted. I will write in this thread what is my experience and solution when we implement this. As you said, a workaround would be to set the consent granted per user in the repository. However, we should see how to automatize this.
    I might open a issue to ForgeRock pointing to this thread and see if they see reasonable to add this feature useful in this sort of scenarios but for now I need to try this work somehow and there is where your idea / workaround comes in handy :-)
    Thanks for your interest

    • This reply was modified 6 years, 6 months ago by Miguel F.
    #8312
     Miguel F
    Participant

    Hi guys,

    I found that a JIRA issue was already open regarding this subject:
    https://bugster.forgerock.org/jira/browse/OPENAM-5093

    They suggest another interesting “workaround” that is modify/customize the OpenAM template corresponding to the User Consent page.
    I guess the idea would be to post the form (accepting it) automatically with JS or something like that.
    Whilst this might be less “intrusive” that the other “workarounds” we discussed here (going to the LDAP field per every user where the consent flag is kept) I guess it might have other col-lateral effects: for instance, probably this template is global for openam (not sure, i would need to find out) and this might not be a solution if you really need to show the consent page to the user and in some other not.

    Regards

    • This reply was modified 6 years, 6 months ago by Miguel F.
    #8314
     Bill Nelson
    Participant

    Modifying the consent form seems like more of a hack than anything. I like to keep things simple, flexible, and in my case known to work. The saved consent attribute (to me) is the best of all worlds. If I want a user to consent (now there’s another conversation with that phrase) then I simply remove that attribute. If I don’t want them to consent, then I populate that attribute during the provisioning process – EASY PEASY!

    #8322
     Miguel F
    Participant

    I agree, Bill, that is not an ideal solution…

    Regards!

    #8333
     tefreestone
    Participant

    We have the same problem. We are thinking about adding an additional scope (e.g. implied_consent) that could turn-off the consent page. We would have to modify the oath2-core (AuthorizationServiceImpl) to check for the implied_scope. It is an easy addition. To your original problem, you could have the rest api request the implied_consent scope and suppress the consent page (or it can be added by default). You will have to make sure you override the oauth2-core jar in the war file to make this work.

    tom freestone

    #8348
     Bill Nelson
    Participant

    Tom, your solution might work, but it sounds like you will most likely be reinventing the same wheel that ForgeRock already provides out of the box.

    Tweaking the data (in my opinion) is always much easier than tweaking the code and either way you slice it, you would need to set your “implied_consent” scope (or not) on a per use basis (i.e. in the user’s profile). That is essentially what you are doing by pre-populating the OAuth2 Service Provider Saved Consent attribute in the user’s profile with a value (or not).

    Here is an example of a Saved Consent attribute for one of my users in OpenDJ (names removed to protect the innocent):

    myOAuth2SavedConsent: myClient cn givenName mail myUniqueUUID

    I set this attribute with these values for any user where I want to bypass the consent page (maybe I do this for users who are employees) and leave this attribute out of the user’s profile for those that I want to provide their consent (maybe I do this for customers). This is an easy toggle where not only can I control display of the consent page, but I can even control the scope if I like. And I do this all through user management provided by the OpenAM REST interface or by using OpenIDM (a much better choice). I could take you into another conversation about how you can automatically set this value in OpenDJ based on other attributes (i.e. ‘userType: employee’ or ‘userType: customer’) by using OpenDJ virtual attributes and that would eliminate the entire coding/user management discussion altogether. But alas, I digress and back to the scenario at hand.

    Once the Saved Consent attribute is populated with the client and scope, then you don’t show the consent page. If there isn’t a Saved Consent, then you do. The beauty behind using what comes out of the box is that the consent page has a check box where the user has the opportunity to save their consent decision and thus bypass all future consents. This decision is stored in the attribute that you specify in the Saved Consent field in the OAuth2 Service Provider definition, so you are basically using all the pieces that come out of the box with OpenAM without any custom code whatsoever and you are doing it in a very flexible way.

    I’m not trying to convince anyone that what I describe is the only way. Tom and Miguel have both provided alternatives and without offending cat lovers out there, there are many ways ‘to skin a cat’. Given all the ForgeRock implementations that I have been part of (and the Sun implementations before that, and iPlanet before that, and Netscape.. you get the picture) I have always found that it is much easier (and safer) if you can use the standard out of the box features and functionality provided by the vendor. It makes implementation, support, and upgrades go much more smoothly.

    #8668
     Tom Kofford
    Participant

    Bill, we (I work with Tom Freestone) looked at doing the same thing you are suggesting. We are wanting to use this approach for many applications that are our own applications. Without going into the reasons for wanting to use OAuth2 to provide SSO across all of our apps, we need a mechanism that will provide OAuth/OIDC SSO without prompting the user. We have several million users we would want to apply this to and it’s for all users. We have tens of thousands of new users every week we would need to add this attribute to at the time they are created. In our situation, this solution isn’t very efficient.

    The solution we have settled on is a one-line code modification in the ‘if’ statement that tests to see if the user has already provided consent. We add a test to check for a certain scope that we set up in the client configuration. If the scope is present, the same action is taken as if the user has previously provided consent. This allows us to set this on a per client basis and provides the functionality we need for all users (current and future) without having to set the attribute for millions of current users and constantly setting it for new users. The scope we check for is not allowed from the client, so control of consent is maintained at the provider.

    While it is source code modification and not necessarily in the spec (although not prohibited?), we’re hoping that it is easy to maintain through upgrades as it is so minimally invasive.

    We’re happy to share if anyone is interested.

Viewing 15 posts - 1 through 15 (of 23 total)

You must be logged in to reply to this topic.

©2022 ForgeRock - we provide an identity and access platform to secure every online relationship for the enterprise market, educational sector and even entire countries. Click to view our privacy policy and terms of use.

Log in with your credentials

Forgot your details?