[keycloak-user] Keycloak adapter with policies returns bad request

Richard van Duijn rjvduijn at gmail.com
Tue Dec 13 08:35:33 EST 2016


Ok, thanks. That did the trick. I was under de assumption that if left
blank, the policy-enforcer would be correctly configured from keycloak
itself. But I now understand we need to specify more specific resource
actions in this keycloak.json file.

Other quick question:
Why is it that when fetching all entitlements from the frontend javascript
with the call:

this.authorization.entitlement('photoz-restful-api').then(function(rpt) {
    console.log('Entitlements loaded...%o',
JSON.stringify(jwt_decode(rpt), null, '  '));
});

Succeeds, and doing the same call from the backend using the configred
Authz client as in the AuthorizationClientExample.java I get an Bad
Request response from keycloak.

private static void obtainAllEntitlements() {
    // create a new instance based on the configuration defined in
keycloak-authz.json
    AuthzClient authzClient = AuthzClient.create();

    // obtian a Entitlement API Token in order to get access to the
Entitlement API.
    // this token is just an access token issued to a client on behalf
of an user with a scope kc_entitlement
    String eat = getEntitlementAPIToken(authzClient);

    // send the entitlement request to the server in order to obtain a
RPT with all permissions granted to the user
    EntitlementResponse response =
authzClient.entitlement(eat).getAll("hello-world-authz-service");
    String rpt = response.getRpt();

    System.out.println("You got a RPT: " + rpt);

    // now you can use the RPT to access protected resources on the
resource server
}


Is this configuration as well?
Thanks!


Op di 13 dec. 2016 om 14:17 schreef Pedro Igor <psilva at redhat.com>:

> It could be related with your policy-enforcer config in keycloak.json.
> There you can associate a scope with a specific HTTP method for a given
> path, maybe this is causing the 401.
>
> If you have everything set correctly, the only thing we can do is debug
> and check what is happening. I don't think this smells like a bug because
> the same scenario works with our tests + photoz app example. But better
> debug your play adapter and see what may be causing this, to make sure.
>
> On 12/13/2016 10:35:21 AM, Richard van Duijn <rjvduijn at gmail.com> wrote:
> Thank you for clarifying that! Much appreciated!
> I'm progressing with my adapter. Using the Photoz example I can login and
> authorize requests going to the photoz-restfull-api (which in my case is my
> play application).
> But one resource refuses to load for non-admin users. Namely the
> /album/create resource returns an Unauthorized. I will try to elaborate on
> what I am currently doing. Hopefully someone can point me the error.
>
>
>    1. The javascript frontend application calls the
>    /photoz-rest-api/album/create resource using a post with the bearerToken
>    received from the login.
>    2. Then my PlayFramework controller Action is intercepted and the
>    bearerToken is verified using the: AdapterRSATokenVerifier.verifyToken()
>    method.
>    3. If succceful the KeycloakAdapterPolicyEnforcer is used to authorize
>    my request using the photoz policies.
>    4. This returns 401 in case of the user Alice, and is accepted in case
>    of Admin.
>
> What I do no understand is that the Policy Evaluator in the admin console
> results in a PERMIT in case of Alice accessing the album resource with
> scope 'Create'. But the KeycloakAdapterPolicyEnforcer tells Alice is
> Unauthorized. Am I missing a vital point in the process?
>
> The entitlements I have for Alice are the following (which clearly states
> the user is allowed to create on the album resource):
> *{*
> * "jti": "6fa19f41-f720-4285-965f-e4373544346c",*
> *  "exp": 1481632355,*
> *  "nbf": 0,*
> *  "iat": 1481632055,*
> *  "iss": "http://127.0.0.1:8080/auth/realms/photoz
> <http://127.0.0.1:8080/auth/realms/photoz>",*
> *  "aud": "photoz-html5-client",*
> *  "sub": "85e9868e-262e-4290-8a23-93f8392cffd7",*
> *  "typ": "Bearer",*
> *  "azp": "photoz-html5-client",*
> *  "nonce": "55b16f6b-5af9-40de-871e-ab8712bd1f57",*
> *  "auth_time": 1481631352,*
> *  "session_state": "73453cd9-01df-4124-a9ca-585352c0e040",*
> *  "name": "Alice In Chains",*
> *  "given_name": "Alice",*
> *  "family_name": "In Chains",*
> *  "preferred_username": "alice",*
> *  "email": "alice at keycloak.org <alice at keycloak.org>",*
> *  "acr": "0",*
> *  "client_session": "2e16eade-c3a2-40ae-b766-3bac6b89d4d4",*
> *  "allowed-origins": [*
> *    "*"*
> *  ],*
> *  "realm_access": {*
> *    "roles": [*
> *      "uma_authorization",*
> *      "user"*
> *    ]*
> *  },*
> *  "resource_access": {*
> *    "photoz-restful-api": {*
> *      "roles": [*
> *        "manage-albums"*
> *      ]*
> *    }*
> *  },*
> *  "authorization": {*
> *    "permissions": [*
> *      {*
> *        "scopes": [*
> *          "urn:photoz.com:scopes:album:view",*
> *          "urn:photoz.com:scopes:album:create"*
> *        ],*
> *        "resource_set_id": "71996b0c-48c1-44c9-8fda-d0ba46b451b7",*
> *        "resource_set_name": "Album Resource"*
> *      },*
> *      {*
> *        "scopes": [*
> *          "urn:photoz.com:scopes:profile:view"*
> *        ],*
> *        "resource_set_id": "0236b990-40dd-4bf3-9a49-25bc3bc6273c",*
> *        "resource_set_name": "User Profile Resource"*
> *      }*
> *    ]*
> *  }*
> *}*
>
> /Richard
>
>
>
> Op do 8 dec. 2016 om 21:11 schreef Pedro Igor <psilva at redhat.com>:
>
> Yeah, I missed that part too :)
>
> Clients marked as bearer-only are not allowed to access the token
> endpoint. However, you can still use bearer-only in your keycloak.json
> (adapter config) to indicate that only requests with a bearer token are
> allowed to access your resource server (backend-client).
>
> Regards.
> Pedro Igor
>
> On 12/8/2016 5:46:25 PM, Richard van Duijn <rjvduijn at gmail.com> wrote:
> Pedro,
> I've imported the json file myself and I was able to fetch the AT with
> postman and things work now. The only difference I see in the server
> configuration is that I had confired the backend-client with Access-Type
> 'Bearer-only', which (after the import) is now 'Confidential'..
>
> In my perception i had to configure the backend-client with a bearer-only
> access-type as it does do any logins just as the 'bearer-only:true' flag in
> the adapter config json.
> Am I mistaken here?
> Well at least I can continue now. but still this seems a bit odd to me.
> Thank you again for your great help! It is much appreciated!
> /Richard
>
> Op do 8 dec. 2016 om 13:49 schreef Richard van Duijn <rjvduijn at gmail.com>:
>
> You've got me confused as well.. haha
>
> No I'm not reaching the lines using the policyEnforcer. The error occurs
> earlier in the process.
>
> Could you perhaps explain what you send in the postman request.
> What is put in it the request is the following:
>
>
> *requestHeaders.put("Authorization",
> BasicAuthHelper.createHeader(Configuration.this.clientId, secret));*
> with the clientId being: *backend-client* and the secret being:
> *6ce718ad-2ab1-42ff-bf01-35a03eab3aee*
> resulting in the header: *Authorization : Basic
> YmFja2VuZC1jbGllbnQ6NmNlNzE4YWQtMmFiMS00MmZmLWJmMDEtMzVhMDNlYWIzYWVl*
>
> Other than that I do not have any clues what is wrong.
>
> The AT request is generated during startup of my backend server. So I do
> not yet have any frontend rest calls containing a bearerToken comming in.
> My assumption is that I can initialize the keycloakDeployment once for my
> entire application and then use it for each call comming in. Am I correct?
> My guess now is that this assumption is wrong.
>
> /Richard
>
>
> Op do 8 dec. 2016 om 13:05 schreef Pedro Igor <psilva at redhat.com>:
>
> On 12/8/2016 7:06:44 AM, Richard van Duijn <rjvduijn at gmail.com> wrote:
> Hi Pedro,
> Thank you for the reply.
>
> Fist I'll answer your questions, then I'll clarify my setup a bit more.
> Please find attached my realm config file as well.
>
>
>    - The realm name was a typo. In the meantime I've reconfigured my
>    realm to ensure the '.' char was not messing up. Turned out not to be the
>    case.
>    - I'm not able to retrieve an AT from keycloak for the backend-client
>    (which is set to bearer-only). With the given Postman request I just get
>    the 400 bad request error and accompanying message.
>
> *Pedro Igor:* I was able to get an AT after importing your realm and
> sending the same postman request. Now I'm confused :) The client is
> backend-client, correct ?
>
>
>    - I've followed the getting started guid up to securing the jboss
>    servlet. I've stopped there as I wanted to use a keycloak distribution in
>    combination with a PlayFramework application (for which there is no adapter
>    available yet).
>
> I've followed the steps from this
> <http://bandrzejczak.com/blog/2015/11/22/single-sign-on-with-keycloak-in-a-sigle-page-application-part-1-slash-2-angular-dot-js/> post
> to get the bearerToken approach working. Using the
> *AdapterRSATokenVerifier* class I was able to verify the bearerToken
> received from the javascript frontend. What I basically have is a filter
> that intercepts the frontend requests, picks up the bearerToken and checks
> it's validity. If valid the resource is accessible otherwise the user
> receives an error.
>
>
> The next step was to include policies in the setup. Setting up the adapter
> for the playFramework was a bit difficult as there is no real documentation
> on that subject, only example implementations like the ones for spring
> security and jetty. But before getting to the complex logic I've added the
> policy-enforcer: {} line in the keycloak.json config file for the
> backend-client. This json is then loaded and used in
> *KeycloakDeploymentBuilder.build(keycloakConfig)*. This is the point
> where it fails, as the config contains the policy-enforcer line, the
> PolicyEnforcer class is initialized, which in turn attempts to retrieve the
> AT from keycloak.
>
> Is there some flaw in my reasoning?
>
>    1. The javascript frontend authenticates itself using the keycloak.js
>    adapter. It adds the accessToken to the Authorization header for the
>    rest-client to pickup
>    2. The rest client (my backend-client) verifies the bearerToken using
>    the AdapterRSATokenVerifier
>    3. Then the rest client checks the authorization using the folliwing
>    lines of code:
>
>
> *final PolicyEnforcer policyEnforcer =
> keycloakDeployment.getPolicyEnforcer();BearerTokenPolicyEnforcer
> bearerTokenPolicyEnforcer = new BearerTokenPolicyEnforcer(policyEnforcer);*
> *final AuthorizationContext authorizationContext =
> bearerTokenPolicyEnforcer.authorize(facade);*
>
> *Pedro Igor:* It looks correct. Although it seems you are not even
> reaching the line above where permissions are actually enforced. Besides,
> make sure you have all bearer token validations in place based on other
> adapters we have.
>
> You are almost there. You just need to figure out why you can't obtain an
> AT from the server even if using postman, curl, etc. I think that if you
> solve this, you will get everything working (or hit some new issue after
> this one :)).
>
>
> Hope this clarifies it a bit. I've attached my realm configuration json
> file. By the way I'm using keycloak 2.4.0-Final.
> Many many thanks for your help!
>
> If this approach is valid I'm hapy to contribute my code to the community
> for others to work with.
> /Richard
>
> Op do 8 dec. 2016 om 01:13 schreef Pedro Igor <psilva at redhat.com>:
>
> Hi Richard,
>
> In your first message, it seems the token endpoint is
> http://127.0.0.1:8080/auth/realms/local.development/protocol/openid-connect/token.Here
>  you are using a realm "local.development".
>
> In your last message with the postman request, you are using a token
> endpoint like this /auth/realms/development/protocol/openid-connect/token.
> Where the realm is "development", the same you have used in keycloak.json.
>
> Would that be a misconfiguration or just a typo ?
>
> Besides, what happens when you send that postman request to the server ?
> Are you able to get a AT ?
>
> This is pretty much what the enforcer does during initialization, obtain a
> AT before querying the Protection API for protected resources. And is what
> your stack trace shows.
>
> If you are not able to obtain a token using the postman request, it
> probably means you have something wrong with your realm/client
> configuration on the server.
>
> Last question, are you able to run any of our authorization examples ? Or
> even successfully follow our Getting Started guide ?
>
> Thanks.
> Pedro Igor
>
> On 12/7/2016 12:05:10 PM, Richard van Duijn <rjvduijn at gmail.com> wrote:
> Forgot to include the postman request.. here it is:
>
> POST /auth/realms/development/protocol/openid-connect/token HTTP/1.1
> Host: 127.0.0.1:8080
> Authorization: Basic
> YmFja2VuZC1jbGllbnQ6NmNlNzE4YWQtMmFiMS00MmZmLWJmMDEtMzVhMDNlYWIzYWVl
> Cache-Control: no-cache
> Content-Type: application/x-www-form-urlencoded
>
> grant_type=client_credentials
>
> /Richard
>
> Op wo 7 dec. 2016 om 15:00 schreef Richard van Duijn <rjvduijn at gmail.com>:
>
> Somehow I do not get any logs in keycloak server.log. I've attempted to
> change the loglevel in standalone.xml to TRACE, but to no avail. Maybe you
> can give me a pointer to which logger I should change to see the correct
> logs show up.
>
> Besides that I've done some debugging using Postman as well. Using the
> following request I get the message:
> {
>     "error": "invalid_client",
>     "error_description": "Bearer-only not allowed"
> }
>
> This is weird to me as the keycloak.json file states that I am connecting
> to a bearer-only client.
>
> Hope this helps to clarify it for you.
> My keycloak.json configuration file looks like this:
>
> {
>   "realm": "development",
>   "bearer-only": true,
>   "auth-server-url": "http://127.0.0.1:8080/auth",
>   "ssl-required": "external",
>   "resource": "backend-client",
>   "use-resource-role-mappings": true,
>   "credentials": {
>     "secret": "SECRETHERE"
>   },
>   "policy-enforcer": {}
> }
>
> Hope this helps to clarify some of your questions.
> /Richard
>
> Op wo 7 dec. 2016 om 12:47 schreef Pedro Igor <psilva at redhat.com>:
>
> Do you get anything in server logs ? It may be related with invalid client
> credentials.
>
> On 12/6/2016 12:41:38 PM, Richard van Duijn <rjvduijn at gmail.com> wrote:
> I'm creating a POC application using playframework and angular. The
> frontend will be protected using the keycloak javascript adapter and the
> backend rest services will be a bearer-only application.
>
> Without the policies turned on in the keycloak.json everything goes well.
> But when I turn the policies by adding "policy-enforcer": { } on for the
> rest services, I get an 400 Bad Request response from the Keycloak server
> during initialization.
> After some debugging I noticed it had to do with the initialization of the
> PolicyEnforcer which attempts to call the following server keycloak
> endpoint:
>
> http://127.0.0.1:8080/auth/realms/local.development/protocol/openid-connect/token
>
> Below you will find the stacktrace and request and response objects.
> Hope someone can point me in the right direction. For instance how to
> configure keycloak logging to get some more details on what the reason for
> the 400 bad request is.
> Many many thanks!
> /Richard
>
>
>
> *Stacktrace*:
>
> at
> org.keycloak.authorization.client.util.HttpMethod.execute(HttpMethod.java:92)
>
> at
> org.keycloak.authorization.client.util.HttpMethodResponse$2.execute(HttpMethodResponse.java:48)
>
> at
> org.keycloak.authorization.client.AuthzClient.obtainAccessToken(AuthzClient.java:112)
>
> at
> org.keycloak.authorization.client.AuthzClient.protection(AuthzClient.java:91)
>
> at
>
> org.keycloak.adapters.authorization.PolicyEnforcer.(PolicyEnforcer.java:57)
>
>
> at
> org.keycloak.adapters.KeycloakDeploymentBuilder.internalBuild(KeycloakDeploymentBuilder.java:126)
>
> at
> org.keycloak.adapters.KeycloakDeploymentBuilder.build(KeycloakDeploymentBuilder.java:135)
>
> at
> security.KeycloakSecurityModule.configure(KeycloakSecurityModule.java:53)
> at com.google.inject.AbstractModule.configure(AbstractModule.java:62)
> ... many google guice calls ...
> at
> play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:129)
>
> at
> play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:121)
>
>
>
> *Request object*:
>
> builder = {RequestBuilder at 12557}
> method = "POST"
> charset = {UTF_8 at 12563} "UTF-8"
> version = null
> uri = {URI at 12564} "
>
> http://127.0.0.1:8080/auth/realms/local.development/protocol/openid-connect/token
> "
> headergroup = {HeaderGroup at 12565} "[Authorization: Basic
> YmFja2VuZC1jbGllbnQ6NmNlNzE4YWQtMmFiMS00MmZmLWJmMDEtMzVhMDNlYWIzYWVl]"
> entity = null
> parameters = {LinkedList at 12566} size = 1
> 0 = {BasicNameValuePair at 12576} "grant_type=client_credentials"
> config = null
>
> *Response object*:
>
> HTTP/1.1 400 Bad Request [Connection: keep-alive, X-Powered-By:
> Undertow/1,
> Server: WildFly/10, Content-Type: application/json, Content-Length: 72,
> Date: Tue, 06 Dec 2016 12:24:28 GMT]
> org.apache.http.conn.BasicManagedEntity at 1f8d1780
> response = {$Proxy16 at 12554} "HTTP/1.1 400 Bad Request [Connection:
> keep-alive, X-Powered-By: Undertow/1, Server: WildFly/10, Content-Type:
> application/json, Content-Length: 72, Date: Tue, 06 Dec 2016 12:24:28 GMT]
> org.apache.http.conn.BasicManagedEntity at 1f8d1780"
> h = {CloseableHttpResponseProxy at 12583}
> original = {BasicHttpResponse at 12584} "HTTP/1.1 400 Bad Request
> [Connection: keep-alive, X-Powered-By: Undertow/1, Server: WildFly/10,
> Content-Type: application/json, Content-Length: 72, Date: Tue, 06 Dec 2016
> 12:24:28 GMT] org.apache.http.conn.BasicManagedEntity at 1f8d1780"
> statusline = {BasicStatusLine at 12556} "HTTP/1.1 400 Bad Request"
> ver = {HttpVersion at 12586} "HTTP/1.1"
> code = 400
> reasonPhrase = "Bad Request"
> entity = {BasicManagedEntity at 12555}
> reasonCatalog = {EnglishReasonPhraseCatalog at 12588}
> locale = {Locale at 12589} "en_US"
> headergroup = {HeaderGroup at 12590} "[Connection: keep-alive,
> X-Powered-By: Undertow/1, Server: WildFly/10, Content-Type:
> application/json, Content-Length: 72, Date: Tue, 06 Dec 2016 12:24:28
> GMT]"
> params = {ClientParamsStack at 12591}
>
> _______________________________________________
> keycloak-user mailing list
> keycloak-user at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/keycloak-user
>
>


More information about the keycloak-user mailing list