[keycloak-dev] Authz services feedback

Marek Posolda mposolda at redhat.com
Wed Jan 30 15:23:51 EST 2019


On 30/01/2019 12:29, Pedro Igor Silva wrote:
> Thanks for the feedback, Marek. Kudos to you too for talking about 
> this stuff.
>
> Answers inline.
>
> On Wed, Jan 30, 2019 at 8:39 AM Marek Posolda <mposolda at redhat.com 
> <mailto:mposolda at redhat.com>> wrote:
>
>     I recently have a chance to play a bit more with authz services when
>     preparing for the devconf demo. Great stuff and cudos to Pedro and
>     all
>     the others who contributed to authorization services!
>
>     I just have few questions and possible suggestions to improve in the
>     future :) Also based on some questions and discussion I had after
>     the talk:
>
>     - My REST service was SpringBoot based and protected by policy
>     enforced
>     configured in the applications.properties like this
>     https://github.com/mposolda/devconf2019-authz/blob/master/devconf2019-service/src/main/resources/application.properties#L23-L32
>
>     . However I was stuck when I wanted to enable UserManagedAccess
>     for my
>     service. The PolicyEnforcerConfig.UserManagedAccessConfig is an empty
>     class and I couldn't figure how to properly add it in the
>     application.properties file. I've tried to add various things in
>     application.properties like this, but none of them helped:
>
>     keycloak.policy-enforcer-config.user-managed-access
>     keycloak.policy-enforcer-config.user-managed-access=
>     keycloak.policy-enforcer-config.user-managed-access= (Just left
>     single
>     space here after equals character) 
>
>
>     As a workaround, I ended with having separate bean to do it
>     programatically -
>     https://github.com/mposolda/devconf2019-authz/blob/master/devconf2019-service/src/main/java/org/keycloak/quickstarts/devconf2019/config/KeycloakUMAConfigResolver.java
>
>     . Is it a bug or is it just me doing something stupid?
>
>
> He had some feedback in the past about that too, but the workaround 
> you did is what people are doing. I've created 
> https://issues.jboss.org/browse/KEYCLOAK-9458.
>
> Similar issue we have when you just want to enable the policy-enforcer 
> without any configuration. You need to specify at least one property 
> of policy-enforcer (or create a bean).
>
>
>
>     - I wonder about possible improvements of keycloak-authz.js and if
>     usability can be a bit improved? More specifically I mean this:
>     -- Handling of the 401 response with UMA ticket from
>     resource-server -
>     Can this be done "automatically"? I meant the flow described here:
>     https://www.keycloak.org/docs/latest/authorization_services/index.html#handling-authorization-responses-from-a-uma-protected-resource-server
>
>     . Maybe the keycloak-authz itself can just handle the response from
>     resource server, then send the AuthorizationRequest to KC with the
>     UMA
>     ticket and then possibly re-send the request to resource-server
>     with new
>     RPT and do this "automatically" without a need to manually handle
>     it by
>     the application like this:
>     https://github.com/keycloak/keycloak-quickstarts/blob/latest/app-authz-uma-photoz/photoz-html5-client/src/main/webapp/js/app.js#L154-L208
>
>     . WDYT?
>
>
> We had that before, but due to some changes in UMA specs, I decided to 
> remove this capability from the adapter. We can discuss to get it back 
> again.

I was thinking that adapter can provide some utility, which will provide 
refreshing of RPT tokens (in case they are expired) and also exchanging 
UMA tickets, which were returned from resource-server for new RPT.

For example adapter can have some utility like "rptProvider", which will 
do something like this (it will be better to have proper state diagram, 
but hopefully you won't be lost in those conditions. Imagine that from 
the point 1, you can go to 1.1 or 1.2):

1) check if there is existing RPT stored. If yes, it will:
1.1) Check if existing RPT is expired. If yes, it will:
1.1.1) try to refresh RPT. If refresh success, then adapter will store 
refreshed RPT and go to (1.2)
1.1.2) If refresh fails, adapter will delete the existing RPT and go to 
step 2
1.2) If existing RPT is not expired, adapter will just call that 
particular "onSuccess" callback method with the RPT
2) If there is no RPT, adapter will use it's accessToken to call 
authorization API
2.1) If calling authorization API fails, there should be "onAuthzError" 
callback called with the error message sent to it as argument (For 
example "request_submitted", so that caller is aware that request was 
saved on KC side to be approved by the resource owner)
2.2) If calling authorization API succeeds, we will store RPT and go to 
(1.2)

--- The "onSuccess" callback will usually invoke the REST service with 
RPT, but service can return UMA ticket in case that RPT is missing some 
permissions. In that case, it should call some builtin function provided 
by the authz client, which will:
3) Try to "parse" the UMA ticket from the response.
3.1) If it's not there, we need to call some "onOtherError" callback method
3.2) If it's there, we will use that UMA ticket to call authorization 
API - hence go again to step 2


Some pseudo-code how the usage of it can look like:

var rptProvider = keycloakAuthzClient.getRptProvider();

// This is the maximum timeout allowed before "rpt" needs to be refreshed
rptProvider.setTokenMinimumTimeToLive(10);

// The "rpt" is guaranteed to NOT be expired. However it may not contain 
permissions needed to invoke resource-server
rptProvider.onSuccess = function(rpt) {
     // Just call the REST service
     var url = 'http://localhost:8080/resource-server';

     var req = new XMLHttpRequest();
     req.open('GET', url, true);
     req.setRequestHeader('Accept', 'application/json');
     req.setRequestHeader('Authorization', 'Bearer ' + rpt);

     req.onreadystatechange = function () {
         if (req.readyState == 4) {
             if (req.status == 200) {
                 alert('Success');
             } else if (req.status == 401) {
                 // We MAY have UMA ticket in the response. Let's just 
call "rptProvider.setUmaResponse" and then re-call "run" .
                 // Internally, the adapter will try to parse UMA ticket 
from the response and exchange this UMA ticket for the RPT from KC server
                 rptProvider.setUmaResponse(req);
                 rptProvider.run();
             }
         }
     }

     req.send();

});

// This callback is called when the call to KC authorization API failed.
// The authzError can be for example "request_submitted", so the caller 
is aware that request was created on Keycloak side and needs to be 
approved by the resource owner
rptProvider.onAuthzError(function(authzError) {

});

// This callback is called on any other error. For example when 
resource-server returns some other error response than "401" with UMA ticket
rptProvider.onOtherError(function(errorDetails) {

});

// This will trigger the described flow
rptProvider.run();


>
>     -- Another thing is refreshing of RPT. It looks that RPT response
>     contains the refresh token, so refreshing of RPTs is possible.
>     However
>     the keycloak-authz.js client doesn't have any support for
>     automatically
>     refreshing RPT token. I mean something similar, which is provided by
>     keycloak.js itself (method "keycloak.updateToken" which automatically
>     refreshes the token if needed). Due this limitation, it seems
>     there is a
>     bug in our quickstart. When you try the quickstart
>     "app-authz-uma-photoz" and you go through the flow like this:
>     - Open http://localhost:8080/photoz-html5-client and login as jdoe
>     - Create some album
>     - Wait 10 minutes (RPT expiration is same like
>     AccessTokenLifespan, so 5
>     minutes by default)
>     - Try to create some album again - now fails with 403 due the RPT
>     expired and no support for refreshing it in the keycloak-authz.js
>     or the
>     application itself.
>     Should I create JIRA for this?
>
>
> Yes, please.
Created https://issues.jboss.org/browse/KEYCLOAK-9464
>
>
>
>     - It seems we don't have any Java based adapter for the frontend
>     clients
>     written in Java? We have Java based authorization client, but that
>     provides just sending REST requests. It doesn't provide things like I
>     mentioned above though (Storing RPT, automatically refreshing RPT,
>     Automatically handling 401 response with the UMA ticket from
>     resource-server and sending the request to KC etc). Any plan to
>     have this?
>
>
> Could we leverage the authz client for that ? If you could create a 
> JIRA with more details about the scenarios we are trying to support, 
> we can start thinking about a solution.

I was thinking about something quite similar like the javascript client 
(keycloak-authz.js) will provide. If we agree on the javascript client, 
hopefully java can have something similar.

Marek

>
> Thanks !
>
>
>     Marek
>
>     _______________________________________________
>     keycloak-dev mailing list
>     keycloak-dev at lists.jboss.org <mailto:keycloak-dev at lists.jboss.org>
>     https://lists.jboss.org/mailman/listinfo/keycloak-dev
>



More information about the keycloak-dev mailing list