如何将客户端访问权限限制为 keycloak 中的一组用户?
How can I restrict client access to only one group of users in keycloak?
我的 awx(ansible tower) 网页在 keycloak
有一个客户端。
我只需要来自一个特定 keycloak
组的用户能够通过此客户端登录。
如何禁止所有其他用户(特定组除外)使用此 keycloak
客户端?
在 Keycloak 管理控制台上,转到“客户端”菜单,select 您的客户端。在客户端配置页面,设置Authorization Enabled: On,点击Save。应该会出现一个新的 Authorization 选项卡,转到它,然后转到下面的 Policies 选项卡,单击 Create Policy 和 select 基于组的策略 。在那里,您可以 restrict access to specific groups,假设您已经通过“群组”菜单定义了您的群组。
--编辑 2019-11-08--
如评论中所述,客户端协议必须设置为openid-connect和访问类型 必须设置为 confidential,才能使 Authorization Enabled 选项可见。
我是这样解决的:
- 在 Keycloak 中创建一个新角色。
- 将此角色分配给组。
- 在 Kycloak 中创建一个新的身份验证脚本。配置登录时允许的角色(例如
user.hasRole(realm.getRole("yourRoleName"))
)。
- 在客户端的设置中,在 "Authentication Flow Overrides" 下,选择刚刚创建的身份验证脚本。
如果有帮助,这里有一个脚本可以帮助为任何客户端实现此行为:如果客户端包含给定角色(此处称为 feature:authenticate
),则脚本会检查用户是否具有角色并显示错误页面(需要在主题中部署的新模板)如果不是。
AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
function authenticate(context) {
var MANDATORY_ROLE = 'feature:authenticate';
var username = user ? user.username : "anonymous";
var client = session.getContext().getClient();
LOG.debug("Checking access to authentication for client '" + client.getName() + "' through mandatory role '" + MANDATORY_ROLE + "' for user '" + username + "'");
var mandatoryRole = client.getRole(MANDATORY_ROLE);
if (mandatoryRole === null) {
LOG.debug("No mandatory role '" + MANDATORY_ROLE + "' for client '" + client.getName() + "'");
return context.success();
}
if (user.hasRole(mandatoryRole)) {
LOG.info("Successful authentication for user '" + username + "' with mandatory role '" + MANDATORY_ROLE + "' for client '" + client.getName() + "'");
return context.success();
}
LOG.info("Denied authentication for user '" + username + "' without mandatory role '" + MANDATORY_ROLE + "' for client '" + client.getName() + "'");
return denyAccess(context, mandatoryRole);
}
function denyAccess(context, mandatoryRole) {
var formBuilder = context.form();
var client = session.getContext().getClient();
var description = !mandatoryRole.getAttribute('deniedMessage').isEmpty() ? mandatoryRole.getAttribute('deniedMessage') : [''];
var form = formBuilder
.setAttribute('clientUrl', client.getRootUrl())
.setAttribute('clientName', client.getName())
.setAttribute('description', description[0])
.createForm('denied-auth.ftl');
return context.failure(AuthenticationFlowError.INVALID_USER, form);
}
根据文档 https://www.keycloak.org/docs/6.0/server_admin/#executions 您必须激活该功能才能使用 "add execution" 添加一些自定义脚本。
bin/standalone.sh|bat -Dkeycloak.profile.feature.scripts=enabled
@Allan feature:authenticate 的解决方案对我来说不错
您可以使用此扩展来限制对特定组的访问:https://github.com/thomasdarimont/keycloak-extension-playground/tree/master/auth-require-group-extension
跟进 Allan 的回答:他的方法很有效(对我来说 ;-)),尽管我在如何部署它方面遇到了一些困难。我是这样做的:
- Bundle script in a JAR file as documented here,通过复制到 standalone/deployments/ 进行部署(参见手册 link)
- 启用脚本:使用
-Dkeycloak.profile.feature.scripts=enabled
启动 Keycloak
- 在您的领域中,创建一个新流。在所需子流中复制浏览器流,并将脚本验证器添加为最终(必需)元素:
- 现在向所有应限制客户角色的客户添加
feature:authenticate
。不承担该角色的用户将无法访问该应用程序。
我找到了一个不需要脚本扩展或对流程进行任何更改的解决方案。
此解决方案的关键是客户端范围。想要授权用户的应用程序需要像电子邮件或 uid 这样的范围,对吧?如果您仅在用户属于特定组时将它们传递给应用程序会怎样?
下面,我的客户端应用名称是App1。
解决方案:
- 转到您的客户端角色(领域 -> 客户端 -> 单击 App1 -> 角色)
- 点击'Add Role' -> 输入名称(例如'access') -> 点击'Save'
- 转到客户端范围(领域 -> 客户端范围)
- 单击您的客户端应用程序所需的范围(例如 'email')
- 通过在下拉列表 'Client Roles'
中选择客户端应用程序 'App1',在 'Scope' 选项卡中分配客户端角色 'access'
现在,您将无法再登录客户端应用程序 App1,因为角色 'access' 未分配给任何用户或组。你可以试试
让我们创建一个新组并为其分配角色和用户。
- 创建组(领域 -> 组 -> 单击 'New' -> 输入名称 'App1 Users' -> 单击保存)
- 在组中,选择 'Role Mappings',在客户端角色下拉列表中选择 'App1',然后分配角色 'access'
- 将用户分配给 'App1 Users'(领域 -> 用户 -> 单击用户 -> 组 -> Select 'App1 用户 -> 单击加入)
瞧,选择的用户可以登录 App1。
我尝试了 Allan 的解决方案,它使用 Keycloak 11.0.3 工作正常,但它有一些下面提到的缺点。这是我的身份验证器脚本解决方案,如果用户至少不是给定组之一的成员,则不会授予用户访问权限。在这种情况下,会显示一条独特的错误消息。
AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
function authenticate(context) {
var allowed_groups = ['foo', 'bar'];
var username = user ? user.username : "anonymous";
var groups = user.getGroups();
var group_array = groups.toArray();
for (var i in group_array) {
var gn = group_array[i].getName();
if (allowed_groups.indexOf(gn) >= 0) {
LOG.info("Access granted for user '" + username + "' for being member of LDAP group '" + gn + "'");
return context.success();
}
}
LOG.info("Access denied for user '" + username + ". for not being member of any of the following LDAP groups: " + allowed_groups);
context.failure(AuthenticationFlowError.IDENTITY_PROVIDER_DISABLED, context.form().setError(
"User doesn't have the required LDAP group membership to view this page", null).createForm("error.ftl"));
return;
}
此解决方案有两个与用户体验相关的小缺点值得一提:
- 当未登录的用户尝试连接到访问被身份验证器脚本拒绝的客户端时,整个身份验证流程被视为失败。这意味着尽管用户提供了正确的凭据
,但他们没有登录到 Keycloak
- 当登录用户尝试连接到访问被身份验证器脚本拒绝的客户端时,会显示 Keycloak 登录页面(不显示任何错误消息),这是具有欺骗性的,因为用户可能会有错误的感觉未登录
此外,如果您维护多个客户端并且您需要为每个客户端检查不同的组(或角色),那么您必须实施与您需要的不同检查一样多的新身份验证流程。简而言之,该解决方案有效,但也有一些缺点。我认为基于组或角色限制访问等简单功能对于身份和访问管理系统来说是必不可少的,应该得到原生支持!
2021 年 - Keycloak 7.4.1.GA
我这样解决了 SAML2
:
添加新的身份验证流程(只需复制现有流程)
添加执行“Group Access Observer”并设置为Required
操作 -> Group Access Observer
行上的配置
填写群组名称
转到您的客户端并将 Authentication flow
更改为立即创建。
此致
使用 Keycloak >= 13.x,您可能想尝试带条件的“Allow/Deny Access”验证器。您可以将角色分配给组并根据角色构建条件。
如果这不够灵活,请试用我构建的 this 库来完全解决该问题。
我的 awx(ansible tower) 网页在 keycloak
有一个客户端。
我只需要来自一个特定 keycloak
组的用户能够通过此客户端登录。
如何禁止所有其他用户(特定组除外)使用此 keycloak
客户端?
在 Keycloak 管理控制台上,转到“客户端”菜单,select 您的客户端。在客户端配置页面,设置Authorization Enabled: On,点击Save。应该会出现一个新的 Authorization 选项卡,转到它,然后转到下面的 Policies 选项卡,单击 Create Policy 和 select 基于组的策略 。在那里,您可以 restrict access to specific groups,假设您已经通过“群组”菜单定义了您的群组。
--编辑 2019-11-08--
如评论中所述,客户端协议必须设置为openid-connect和访问类型 必须设置为 confidential,才能使 Authorization Enabled 选项可见。
我是这样解决的:
- 在 Keycloak 中创建一个新角色。
- 将此角色分配给组。
- 在 Kycloak 中创建一个新的身份验证脚本。配置登录时允许的角色(例如
user.hasRole(realm.getRole("yourRoleName"))
)。 - 在客户端的设置中,在 "Authentication Flow Overrides" 下,选择刚刚创建的身份验证脚本。
如果有帮助,这里有一个脚本可以帮助为任何客户端实现此行为:如果客户端包含给定角色(此处称为 feature:authenticate
),则脚本会检查用户是否具有角色并显示错误页面(需要在主题中部署的新模板)如果不是。
AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
function authenticate(context) {
var MANDATORY_ROLE = 'feature:authenticate';
var username = user ? user.username : "anonymous";
var client = session.getContext().getClient();
LOG.debug("Checking access to authentication for client '" + client.getName() + "' through mandatory role '" + MANDATORY_ROLE + "' for user '" + username + "'");
var mandatoryRole = client.getRole(MANDATORY_ROLE);
if (mandatoryRole === null) {
LOG.debug("No mandatory role '" + MANDATORY_ROLE + "' for client '" + client.getName() + "'");
return context.success();
}
if (user.hasRole(mandatoryRole)) {
LOG.info("Successful authentication for user '" + username + "' with mandatory role '" + MANDATORY_ROLE + "' for client '" + client.getName() + "'");
return context.success();
}
LOG.info("Denied authentication for user '" + username + "' without mandatory role '" + MANDATORY_ROLE + "' for client '" + client.getName() + "'");
return denyAccess(context, mandatoryRole);
}
function denyAccess(context, mandatoryRole) {
var formBuilder = context.form();
var client = session.getContext().getClient();
var description = !mandatoryRole.getAttribute('deniedMessage').isEmpty() ? mandatoryRole.getAttribute('deniedMessage') : [''];
var form = formBuilder
.setAttribute('clientUrl', client.getRootUrl())
.setAttribute('clientName', client.getName())
.setAttribute('description', description[0])
.createForm('denied-auth.ftl');
return context.failure(AuthenticationFlowError.INVALID_USER, form);
}
根据文档 https://www.keycloak.org/docs/6.0/server_admin/#executions 您必须激活该功能才能使用 "add execution" 添加一些自定义脚本。
bin/standalone.sh|bat -Dkeycloak.profile.feature.scripts=enabled
@Allan feature:authenticate 的解决方案对我来说不错
您可以使用此扩展来限制对特定组的访问:https://github.com/thomasdarimont/keycloak-extension-playground/tree/master/auth-require-group-extension
跟进 Allan 的回答:他的方法很有效(对我来说 ;-)),尽管我在如何部署它方面遇到了一些困难。我是这样做的:
- Bundle script in a JAR file as documented here,通过复制到 standalone/deployments/ 进行部署(参见手册 link)
- 启用脚本:使用
-Dkeycloak.profile.feature.scripts=enabled
启动 Keycloak
- 在您的领域中,创建一个新流。在所需子流中复制浏览器流,并将脚本验证器添加为最终(必需)元素:
- 现在向所有应限制客户角色的客户添加
feature:authenticate
。不承担该角色的用户将无法访问该应用程序。
我找到了一个不需要脚本扩展或对流程进行任何更改的解决方案。
此解决方案的关键是客户端范围。想要授权用户的应用程序需要像电子邮件或 uid 这样的范围,对吧?如果您仅在用户属于特定组时将它们传递给应用程序会怎样?
下面,我的客户端应用名称是App1。
解决方案:
- 转到您的客户端角色(领域 -> 客户端 -> 单击 App1 -> 角色)
- 点击'Add Role' -> 输入名称(例如'access') -> 点击'Save'
- 转到客户端范围(领域 -> 客户端范围)
- 单击您的客户端应用程序所需的范围(例如 'email')
- 通过在下拉列表 'Client Roles' 中选择客户端应用程序 'App1',在 'Scope' 选项卡中分配客户端角色 'access'
现在,您将无法再登录客户端应用程序 App1,因为角色 'access' 未分配给任何用户或组。你可以试试
让我们创建一个新组并为其分配角色和用户。
- 创建组(领域 -> 组 -> 单击 'New' -> 输入名称 'App1 Users' -> 单击保存)
- 在组中,选择 'Role Mappings',在客户端角色下拉列表中选择 'App1',然后分配角色 'access'
- 将用户分配给 'App1 Users'(领域 -> 用户 -> 单击用户 -> 组 -> Select 'App1 用户 -> 单击加入)
瞧,选择的用户可以登录 App1。
我尝试了 Allan 的解决方案,它使用 Keycloak 11.0.3 工作正常,但它有一些下面提到的缺点。这是我的身份验证器脚本解决方案,如果用户至少不是给定组之一的成员,则不会授予用户访问权限。在这种情况下,会显示一条独特的错误消息。
AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
function authenticate(context) {
var allowed_groups = ['foo', 'bar'];
var username = user ? user.username : "anonymous";
var groups = user.getGroups();
var group_array = groups.toArray();
for (var i in group_array) {
var gn = group_array[i].getName();
if (allowed_groups.indexOf(gn) >= 0) {
LOG.info("Access granted for user '" + username + "' for being member of LDAP group '" + gn + "'");
return context.success();
}
}
LOG.info("Access denied for user '" + username + ". for not being member of any of the following LDAP groups: " + allowed_groups);
context.failure(AuthenticationFlowError.IDENTITY_PROVIDER_DISABLED, context.form().setError(
"User doesn't have the required LDAP group membership to view this page", null).createForm("error.ftl"));
return;
}
此解决方案有两个与用户体验相关的小缺点值得一提:
- 当未登录的用户尝试连接到访问被身份验证器脚本拒绝的客户端时,整个身份验证流程被视为失败。这意味着尽管用户提供了正确的凭据 ,但他们没有登录到 Keycloak
- 当登录用户尝试连接到访问被身份验证器脚本拒绝的客户端时,会显示 Keycloak 登录页面(不显示任何错误消息),这是具有欺骗性的,因为用户可能会有错误的感觉未登录
此外,如果您维护多个客户端并且您需要为每个客户端检查不同的组(或角色),那么您必须实施与您需要的不同检查一样多的新身份验证流程。简而言之,该解决方案有效,但也有一些缺点。我认为基于组或角色限制访问等简单功能对于身份和访问管理系统来说是必不可少的,应该得到原生支持!
2021 年 - Keycloak 7.4.1.GA
我这样解决了 SAML2
:
添加新的身份验证流程(只需复制现有流程)
添加执行“Group Access Observer”并设置为
Required
操作 ->
Group Access Observer
行上的配置填写群组名称
转到您的客户端并将
Authentication flow
更改为立即创建。
此致
使用 Keycloak >= 13.x,您可能想尝试带条件的“Allow/Deny Access”验证器。您可以将角色分配给组并根据角色构建条件。
如果这不够灵活,请试用我构建的 this 库来完全解决该问题。