Keycloak Keycloack:用户可以通过登录到另一个领域来访问一个领域

Keycloak Keycloack:用户可以通过登录到另一个领域来访问一个领域,keycloak,openresty,Keycloak,Openresty,我有一个nginx/openresty客户端到keycloack服务器,以便使用openid进行授权。 我使用允许访问代理背后的服务 我在两个不同的领域为不同的服务创建了两个客户端 问题是,在用户在第一个域(例如https:///auth/realms//protocol/openid-connect/auth?response_type=code&client_id=openresty&state=...........,他也可以直接访问realm2上的其他服务 这是怎么回事?我如何确保用户只

我有一个nginx/openresty客户端到keycloack服务器,以便使用openid进行授权。 我使用允许访问代理背后的服务

我在两个不同的领域为不同的服务创建了两个客户端


问题是,在用户在第一个域(例如
https:///auth/realms//protocol/openid-connect/auth?response_type=code&client_id=openresty&state=...........
,他也可以直接访问realm2上的其他服务

这是怎么回事?我如何确保用户只能在其认证所针对的领域访问客户端

我如何确保在注销后,用户在重新登录之前将无法再获得访问权限

[编辑详情] 下面是这两个服务的nginx.conf。 用户首先访问
https:///service_1/
并被重定向到keycloack以提供realm1的密码。他提供该服务,并能够访问服务1

但是,如果之后他试图访问
https:///service_2/
,他不再需要进行身份验证,但可以登录,尽管该服务是关于一个不同领域的客户,具有不同的客户机密

。。。。。 位置/服务\u 1/{

    access_by_lua_block {
        local opts = {
            redirect_uri_path = "/service_1/auth", -- we are send here after auth
            discovery = "https://<my-server>/keycloak/auth/realms/realm1/.well-known/openid-configuration",
            client_id = "openresty",
            client_secret = "<client1-secret>",
            session_contents = {id_token=true} -- this is essential for safari!
        }
        -- call introspect for OAuth 2.0 Bearer Access Token validation
        local res, err = require("resty.openidc").authenticate(opts)

        if err then
            ngx.status = 403
            ngx.say(err)
            ngx.exit(ngx.HTTP_FORBIDDEN)
        end
    }

    # I disabled caching so the browser won't cache the site.
    expires           0;
    add_header        Cache-Control private;

    proxy_pass http://<server-for-service1>:port1/foo/;
    proxy_set_header Host $http_host;

    proxy_http_version 1.1;
    proxy_redirect off;
    proxy_buffering off;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

}
通过块访问{
本地选项={
重定向\u uri\u path=“/service\u 1/auth”
发现=”https:///keycloak/auth/realms/realm1/.well-known/openid-configuration",
客户端\u id=“openresty”,
客户_secret=“”,
session_contents={id_token=true}——这对于safari来说是必不可少的!
}
--OAuth 2.0承载访问令牌验证的调用内省
本地res,err=require(“resty.openidc”).authenticate(opts)
如果有错误,那么
ngx.status=403
ngx.say(呃)
ngx.exit(禁止ngx.HTTP_)
结束
}
#我禁用了缓存,因此浏览器不会缓存站点。
过期0;
添加_头缓存控制私有;
代理传递http://:port1/foo/;
代理设置头主机$http\U主机;
proxy_http_版本1.1;
代理_重定向关闭;
代理缓冲关闭;
代理设置头升级$http\U升级;
代理设置头连接“升级”;
}

location /service_2/ {

    access_by_lua_block {
        local opts = {
            redirect_uri_path = "/service_2/auth", -- we are send here after auth
            discovery = "https://<my-server>/keycloak/auth/realms/realm2/.well-known/openid-configuration",
            client_id = "openresty",
            client_secret = "client2-secret",
            session_contents = {id_token=true} -- this is essential for safari!
        }
        -- call introspect for OAuth 2.0 Bearer Access Token validation
        local res, err = require("resty.openidc").authenticate(opts)

        if err then
            ngx.status = 403
            ngx.say(err)
            ngx.exit(ngx.HTTP_FORBIDDEN)
        end
    }

    # I disabled caching so the browser won't cache the site.
    expires           0;
    add_header        Cache-Control private;

    proxy_pass http://<server-for-service2>:port2/bar/;
    proxy_set_header Host $http_host;

    proxy_http_version 1.1;
    proxy_redirect off;
    proxy_buffering off;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

}
位置/服务\u 2/{
通过_lua_块访问_{
本地选项={
重定向_uri_path=“/service_2/auth”-我们在auth之后发送到这里
发现=”https:///keycloak/auth/realms/realm2/.well-known/openid-configuration",
客户端\u id=“openresty”,
client_secret=“client2 secret”,
session_contents={id_token=true}——这对于safari来说是必不可少的!
}
--OAuth 2.0承载访问令牌验证的调用内省
本地res,err=require(“resty.openidc”).authenticate(opts)
如果有错误,那么
ngx.status=403
ngx.say(呃)
ngx.exit(禁止ngx.HTTP_)
结束
}
#我禁用了缓存,因此浏览器不会缓存站点。
过期0;
添加_头缓存控制私有;
代理传递http://:port2/bar/;
代理设置头主机$http\U主机;
proxy_http_版本1.1;
代理_重定向关闭;
代理缓冲关闭;
代理设置头升级$http\U升级;
代理设置头连接“升级”;
}
[编辑详情2]

我使用的是LuaRestyOpenIDC版本1.7.2,但根据两个版本代码的差异,我编写的所有内容都应该代表1.7.4

我可以从调试级日志中清楚地看到,会话是在第一次访问期间创建的,然后在第二个域上重用,这是错误的,因为第二次访问仍然有第一个域的令牌。。。下面是对realm2的授权看起来是什么样子的…:

2021/04/28 12:56:41 [debug] 2615#2615: *4617979 [lua] openidc.lua:1414: authenticate(): session.present=true, session.data.id_token=true, session.data.authenticated=true, opts.force_reauthorize=nil, opts.renew_access_token_on_expiry=nil, try_to_renew=true, token_expired=false
2021/04/28 12:56:41 [debug] 2615#2615: *4617979 [lua] openidc.lua:1470: authenticate(): id_token={"azp":"realm1","typ":"ID","iat":1619614598,"iss":"https:\/\/<myserver>\/keycloak\/auth\/realms\/realm1","aud":"realm1","nonce":"8c8ca2c4df2...b26"
,"jti":"1c028c65-...0994f","session_state":"0e1241e3-66fd-4ca1-a0dd-c0d1a6a5c708","email_verified":false,"sub":"25303e44-...e2c1757ae857","acr":"1","preferred_username":"logoutuser","auth_time":1619614598,"exp":1619614898,"at_hash":"5BNT...j414r72LU6g"}
2021/04/28 12:56:41[debug]2615#2615:*4617979[lua]openidc.lua:1414:authenticate():session.present=true,session.data.id\u-token=true,session.data.authenticated=true,opts.force\u-reauthorize=nil,opts.renew\u-access\u-token\u-on\u-expired=nil=nil,try\u-to\u-renew=true,token\u-expired=false
2021/04/28 12:56:41[debug]2615#2615:*4617979[lua]openidc.lua:1470:authenticate():id_令牌={“azp”:“realm1”,“typ”:“id”,“iat”:1619614598,“iss”:“https:\/\/\/keydave\/auth\/realms\/realm1”,“aud”:“realm1”,“nonce”:“8c8ca2c4df2…”b26”
“jti”:“1c028c65-…0994f”,“会话状态”:“0e1241e3-66fd-4ca1-a0dd-c0d1a6a5c708”,“电子邮件已验证”:false,“sub”:“25303e44-…e2c1757ae857”,“acr”:“1”,“首选用户名”:“登录用户”,“验证时间”:1619614598,“实验”:1619614898,“at哈希”:“5BNT…j414r72LU6g”}

好的,这花了我一些时间。也可能是大多数教程都会留下这样一个漏洞(仅在一个nginx使用多个域的设置中),即一个域的身份验证访问将允许对任何其他域的身份验证访问。

教程中的一个典型自动验证调用是:

location /service1/ {

    access_by_lua_block {
        local opts = {
            redirect_uri_path = "/realm1/authenticated",
            discovery = "https://<myserver>/keycloak/auth/realms/realm1/.well-known/openid-configuration",
            client_id = "client1",
            client_secret = <........>,
            session_contents = {id_token=true} -- this is essential for safari!
        }
        -- call introspect for OAuth 2.0 Bearer Access Token validation
        local res, err = require("resty.openidc").authenticate(opts)

        if err then
            ngx.status = 403
            ngx.say(err)
            ngx.exit(ngx.HTTP_FORBIDDEN)
        end
    }

    # I disbled caching so the browser won't cache the site.
    expires           0;
    add_header        Cache-Control private;

    proxy_pass http://realm1-server:port/service1/;
    proxy_set_header Host $http_host;

    proxy_http_version 1.1;
    proxy_redirect off;
    proxy_buffering off;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

}
location /service2/ {
 <same for ream2> 
}
位置/服务1/{
通过_lua_块访问_{
本地选项={
重定向_uri_path=“/realm1/authenticated”,
发现=”https:///keycloak/auth/realms/realm1/.well-known/openid-configuration",
客户_id=“client1”,
客户机密码=,
session_contents={id_token=true}——这对于safari来说是必不可少的!
}
--OAuth 2.0承载访问令牌验证的调用内省
本地res,err=require(“resty.openidc”).authenticate(opts)
如果有错误,那么
ngx.status=403
ngx.say(呃)
ngx.exit(禁止ngx.HTTP_)
结束
}
#我取消了缓存,因此浏览器不会缓存站点。
过期0;
添加_头缓存控制私有;
代理通行证http://realm1-server:port/service1/;
代理设置头主机$http\U主机;
proxy_http_版本1.1;
代理权
    access_by_lua_block {
        local opts = {
            redirect_uri_path = "/realm1/authenticated",
            discovery = "https://<myserver>/keycloak/auth/realms/realm1/.well-known/openid-configuration",
            client_id = "client1",
            client_secret = <........>,
            session_contents = {id_token=true} -- this is essential for safari!
        }
        -- call introspect for OAuth 2.0 Bearer Access Token validation
        local res, err = require("resty.openidc").authenticate(opts,nil,nil,{name=opts.client_id})

        if (err or ( res.id_token.azp ~= opts.client_id ) ) then
            ngx.status = 403
            ngx.say(err)
            ngx.exit(ngx.HTTP_FORBIDDEN)
        end
    }
    <..................no changes here................>
}
location /service2/ {
 <same for ream2> 
}