[keycloak-dev] Authz services feedback
Pedro Igor Silva
psilva at redhat.com
Thu Jan 31 08:08:03 EST 2019
Thanks!
On Thu, Jan 31, 2019 at 10:26 AM Marek Posolda <mposolda at redhat.com> wrote:
> Cool, so I created:
> https://issues.jboss.org/browse/KEYCLOAK-9468 - Improve keycloak-authz.js
> to automatically exchange UMA tickets and refresh tokens
> https://issues.jboss.org/browse/KEYCLOAK-9469 - Improve authorization
> java client to support automatically exchange UMA tickets and refresh RPT
> tokens
>
> Already created yesterday for a bug in quickstarts (cased by expired RPT):
> https://issues.jboss.org/browse/KEYCLOAK-9464 app-authz-uma-photoz
> quickstart doesn't handle expired RPT
>
> Marek
>
> On 30/01/2019 21:40, Pedro Igor Silva wrote:
>
> +1 for keycloak-authz.js related changes.
>
> Regarding the java adapter, I think we could leverage our
> java authz client for that. So, +1 for a JIRA.
>
> On Wed, Jan 30, 2019 at 6:23 PM Marek Posolda <mposolda at redhat.com> wrote:
>
>> 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>
>> 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
>>> https://lists.jboss.org/mailman/listinfo/keycloak-dev
>>>
>>
>>
>
More information about the keycloak-dev
mailing list