On Tue, Jun 4, 2019 at 11:46 AM Jahn, Lasse <
Lasse.Jahn(a)student.hpi.uni-potsdam.de> wrote:
Hmm ok,
But is the decision maid in keycloak or inside the keycloak Adapter ?
I don’t really get why the adapter has to fetch the resources ? Couldn’t
the adapter send the requested url from req object and the decision which
resource is meant happens in the keycloak Service itself?!
Your point is correct, but our authorization request is based on the
resource/scopes you want to evaluate permissions too. Subject to
improvements though.
So the policy, permissions, resources only stay inside of keycloak and the
adapter only receives a access grant or access deny which he than enforces.
Or in other words, that the adapter is only the PEP (policy enforcement
point) and keycloak service is the PDP (policy decision point).
That is how it works. By fetching resources, I mean obtaining from Keycloak
the mappings for URIs <-> Resources IDs so that we can send authorization
requests accordingly.
On 4. Jun 2019, at 14:47, Pedro Igor Silva <psilva(a)redhat.com> wrote:
On Tue, Jun 4, 2019 at 9:28 AM Jahn, Lasse <
Lasse.Jahn(a)student.hpi.uni-potsdam.de> wrote:
> So just to make it sure, if I use the node adapter the resource URIs in
> the keycloak admin console are not used yet?
>
Yes. That is why you need to use the enforcer in the route so that you
associate a resource with the route/path.
In other adapters, the enforcer is capable of fetching and caching
resources from the server based on the requested URI. So you don't need to
do this association manually.
>
> I would have thought that the backend sends a request to keycloak sending
> the
> - bearer token (for all credentials and user information...)
> - request object (to have the requested resource)
>
> And then keycloak evaluates and only answers grant or deny ?!
>
> Is this decision maid inside the adapter or keycloak?
>
Yes, that is how it works. The missing part is the enforcer using the
requested URI to match a resource in Keycloak so that permissions can be
enforced.
>
> On 4. Jun 2019, at 14:06, Pedro Igor Silva <psilva(a)redhat.com> wrote:
>
> Differently than other adapters, the NodeJS adapter does not fetch
> resources from the server, so you need to use the enforcer on each route:
>
> app.get('/api/users', keycloak.enforcer(['users'])
> app.get('/api/devices', keycloak.enforcer(['devices'])
>
> Please, create an RFE if you the current behavior is not enough for you.
>
> On Tue, Jun 4, 2019 at 5:23 AM Lasse Jahn <lasse.jahn(a)student.hpi.de>
> wrote:
>
>> Hey Pedro,
>>
>> sorry for the really late reply. There've been some other issues I had
>> to fix first before I could come back to authorization. But now I try to
>> get this done.
>>
>> Unfortunately I don't really get the thing with the resources and the
>> regarding URIs.
>>
>> I want the keycloak enforcer middleware only called at the one point,
>> like I explained. Based on the called route (e.g. /api/users or
>> api/devices) I would like to have only the permissions of the resource
>> evaluated.
>>
>> I guess somehow I just miss a thing and it should be easy possible.
>>
>>
>> What I did:
>> 1. Created 2 resources (users, devices with URIs "/api/users" or
>> "/api/devices"
>> 2. Created 2 permission and policy (users grant always, devices deny
>> always)
>> 3. Added the keycloak enforcer middleware before the router.
>>
>> ****
>> app.use('/api', keycloak.enforcer(['users',
'devices']), routes);
>> ****
>>
>> Unfortunately when I access /api/devices this is allowed.
>>
>> I would like to create resources on the client and have one policy per
>> each to decide. Is it possible, that the enforcer checks which resource is
>> requested and uses only that one.
>>
>> If not what is the URI of a resource for?
>>
>>
>> Regards Lasse
>>
>>
>> On 15.05.19 19:55, Pedro Igor Silva wrote:
>>
>>
>>
>> On Wed, May 15, 2019 at 8:52 AM Lasse Jahn <lasse.jahn(a)student.hpi.de>
>> wrote:
>>
>>> Hi Pedro,
>>>
>>> thanks for the quick reply. So I got it working now, that the resource
>>> I created is enforcing the one policy. For a single resource this is great.
>>>
>>> Later on I would like to have an multi tenant solution, short
>>> explanation what I mean:
>>>
>>> Different companies have the same functionality but maybe want to
>>> change the restriction for there self. But still with only one backend
>>> application running. So each company should get one realm with the backend
>>> application registered as a client. When they call the api the backend
>>> should enforce the policies of the company specific client.
>>>
>>> Therefore I have 2 questions:
>>>
>>> 1. Is it possible to configure the enforcer to enforce all policies for
>>> all resources only depending on the requested on the path. So I only to
>>> have to add the middleware once before the express router. So for example
>>> we have a route /api/devices and /api/users (GET,POST,DELETE each). Both
>>> are represented by a resource in the keycloak admin console.
>>>
>>> I would like to have something like this:
>>>
>>> router.js
>>>
>>> ****
>>>
>>> const express = require('express');
>>> const router = express.Router();
>>> const users = require('../controllers/users.controller');
>>> const devices = require('../controllers/devices.controller');
>>>
>>> router.post('/users/', users.create);
>>> router.delete('/users/', users.deleteAll);
>>> router.get('/users/', users.findAll);
>>>
>>> router.post('/devices/', devies.create);
>>> router.delete('/devices/', devicese.deleteAll);
>>> router.get('/devices/', devices.findAll);
>>>
>>> module.exports = router;
>>>
>>> ****
>>>
>>>
>>> app.js
>>>
>>> ****
>>>
>>> .... //all from before
>>>
>>> app.use('/api', keycloak.enforcer(__SOME_CONFIG__), routes);
>>>
>>> ****
>>>
>>>
>>> I dont want to write keycloak.enforcer(...) to each line of users or
>>> devices...
>>>
>>> Maybe this can done by the claims and the context information? But if
>>> yes I don't get how.
>>>
>> Yes, by using claims you are allowed to use them in your policies. Here
>> is an example:
>>
https://github.com/keycloak/keycloak-quickstarts/blob/latest/app-authz-re....
>> More details here
>>
https://www.keycloak.org/docs/latest/authorization_services/index.html#ex...
>> .
>>
>> Your keycloak.enforce would be similar to
>>
https://github.com/keycloak/keycloak-nodejs-connect/blob/master/test/fixt...
>> .
>>
>>>
>>> 2. For now the solution is only single tenant, but If I want to have it
>>> multi tenant and have realm per company with similar clients (only
>>> different in policies and permissions). Do you have an idea how I can solve
>>> the problem that the keycloak object is configured realm specific?
>>> I would probably build a middleware which checks for a custom HTTP
>>> header or looks for a subdomain for referencing the company. Depending on
>>> the company I would set the keycloak object.
>>> Do you think this can work ? Or do you have a better idea?
>>>
>> AFAIK, this is how you do it. So that accordingly with the request you
>> build a new Keycloak object using a specific realm.
>>
>>
>>>
>>> Some suggestions for your documentation:
>>>
>>> - Could you somewhere describe what the middleware option protected is
>>> doing? The Logout, ... options are explained, but the protected I
couldn't
>>> find.
>>> - Your default resource is called 'Default Resource' but in the
example
>>> the resource is renamed to 'resource' the rest is untouched and
default
>>> config. Maybe a comment or adjustment of the example might be helpful.
>>>
>> Thanks for the feedback. Feel free to create a JIRA so that we can track
>> and plan the improvements you are proposing.
>>
>>>
>>> Regards,
>>> Lasse
>>> On 14.05.19 20:33, Pedro Igor Silva wrote:
>>>
>>> Hi,
>>>
>>> We've added more docs to NodeJS PEP recently [1]. They should be
>>> available in the next release. Please, let me know if that is enough or if
>>> we need to add more information.
>>>
>>> In your case, this code:
>>>
>>> app.use('/api', keycloak.enforcer({WHAT_COMES_HERE}), routes);
>>>
>>> Would be:
>>>
>>> app.use('/api',
keycloak.enforcer('{resource_name}:{resource_scope}'),
>>> routes);
>>>
>>> If you have a resource in Keycloak called "foo" and a scope
associated
>>> with this resource called "bar", the code would be:
>>>
>>> app.use('/api', keycloak.enforcer('foo:bar'), routes);
>>>
>>> Hope it helps.
>>>
>>> [1]
https://github.com/keycloak/keycloak-documentation/pull/654
>>>
>>> On Tue, May 14, 2019 at 1:25 PM Jahn, Lasse wrote:
>>>
>>>> Hello,
>>>>
>>>> It's the first time writing to keycloak mailing list (I hope this is
>>>> the correct one?) so excuse if I forget to provide some information or
any
>>>> other mistakes ..
>>>> Sorry for the text wall.
>>>>
>>>> Shortly what I try to do (maybe I got something completely wrong):
>>>> I create a backend (node.js Bearer Only) which shall offer an REST
>>>> api. Partially it is used via a frontend (keycloak-clients) or directly
by
>>>> some devices.
>>>> In general I try to create an application with a lot of CRUD. User
>>>> Management is done in keycloak and only I forward these requests to the
>>>> admin REST Api. Other stuff like the devices ... I store in a separate
>>>> database.
>>>> So the backend is the abstraction layer for frontend and other
>>>> use-cases.
>>>>
>>>> So far so good, but for the beginning it was enough to check weather
>>>> the request comes from an authenticated person or not, so all handled
via
>>>> keycloak.protect() The Token from the authenticated person was passed
>>>> But now I'd want to offer different authorization level (can differ
>>>> due to reasons of multitenancy, why I want to solve this via policies
and
>>>> co in admin-console inside the client configuariton) because the normal
>>>> user shall have access to only some routes and the management shall have
>>>> full access to the api, but of course don't need the keycloak admin
access.
>>>> So I enabled the service account for my backend client and gave this
>>>> one the realm-admin role so the client has access to everything and I
can
>>>> handle the authorization inside the backend client it self (using
policies,
>>>> permissions, .. inside the admin-console).
>>>> (Just in case no one gets what I'm talking about. Fixing [1] should
>>>> help me fixing my issue I guess)
>>>>
>>>> Setup
>>>> - node.js application using express
>>>> - registered as single client in keycloak admin-console (confidential,
>>>> but config inside the code is bearer-only)
>>>> - Keycloak is running in a docker-container (version 4.5)
>>>> - all services are running in a docker-compose network and are behind
>>>> a reverse proxy for common uri
>>>> - enabled Authorization in client and changed the default policy to
>>>> Negative to always deny => to see if it is enforced)
>>>>
>>>> My Problem
>>>> I don't understand how to use the policies, permissions and Co I
>>>> created in the admin-console inside the backend it self. How do I
enforce
>>>> that these are used?
>>>> I tried to check different examples and documentation, but could get
>>>> it working.
>>>> The last thing I found was that the entitlement api was removed, but a
>>>> policy-enforcer was added to the nodejs adapter. In the documentation
for
>>>> the policy-enforcer [2] I couldn't find a documentation of the
middleware
>>>> (keycloak.enforcer({}) [3][4]).
>>>>
>>>> My Code
>>>>
>>>> *****
>>>> app.js
>>>>
>>>> const express = require('express');
>>>> const app = express();
>>>> const Keycloak = require('keycloak-connect');
>>>> const session = require('express-session');
>>>> const routes = require('./routes/index');
>>>>
>>>>
>>>> const kcConfig = {
>>>> 'realm': 'master',
>>>> 'bearer-only': true,
>>>> 'auth-server-url':
`https://DOMAIN/auth<https://domain/auth>`,
>>>> 'ssl-required': 'all',
>>>> 'resource': 'fm-backend',
>>>> 'credentials': {
>>>> secret: 'SOME_SECRET',
>>>> },
>>>> 'confidential-port': 0,
>>>> 'policy-enforcer': { //tried
with
>>>> an without this, changed nothing
>>>> 'enforcement-mode': 'ENFORCING',
>>>> },
>>>> };
>>>>
>>>> const memoryStore = new session.MemoryStore();
>>>> const keycloak = new Keycloak({ memoryStore }, kcConfig);
>>>>
>>>> app.use(keycloak.middleware({ logout: '/api/logout', protected:
>>>> '/api/gates' }));
>>>>
>>>> // used before, worked for well for authentication
>>>> app.use('/api', keycloak.protect(), routes);
>>>>
>>>> // now unfortunately I don't understand how to use
keycloak.enforcer()
>>>> middleware
>>>> app.use('/api', keycloak.enforcer({WHAT_COMES_HERE}), routes);
>>>>
>>>> module.exports = app;
>>>>
>>>> *****
>>>>
>>>> [1]
>>>>
https://stackoverflow.com/questions/53722033/how-to-enable-policy-enforci...
>>>> [2]
>>>>
https://keycloak-docs.github.io/deploy-docs/dev/master/authorization_serv...
>>>> [3]
>>>>
https://github.com/keycloak/keycloak-documentation/blob/master/securing_a...
>>>> [4]
>>>>
https://github.com/keycloak/keycloak-nodejs-connect/blob/master/example/i...
>>>>
>>>>
>>>> Any Help is appreciated :)
>>>>
>>>>
>>>> With kind regards
>>>> Lasse
>>>> _______________________________________________
>>>> keycloak-user mailing list
>>>> keycloak-user(a)lists.jboss.org
>>>>
https://lists.jboss.org/mailman/listinfo/keycloak-user
>>>>
>>>