[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