3.5. 使用 OpenID Connect 来保护 OpenShift 上的 JBoss EAP 应用程序
使用 JBoss EAP 原生 OpenID Connect (OIDC)客户端来委托使用外部 OpenID 供应商的身份验证。OIDC 是一个身份层,它允许客户端(如 JBoss EAP)根据 OpenID 供应商执行的身份验证来验证用户的身份。
elytron-oidc-client
子系统和 elytron-oidc-client
Galleon 层在 JBoss EAP 中提供原生 OIDC 客户端,以与 OpenID 供应商连接。JBoss EAP 根据您的 OpenID 提供程序配置自动为您的应用程序创建虚拟安全域。
您可以通过三种不同的方式配置 elytron-oidc-client
子系统:
-
在部署中添加
oidc.json
。 -
运行 CLI 脚本以配置
elytron-oidc-client
子系统。 -
定义环境变量,以在 OpenShift 上的 JBoss EAP 服务器启动时配置
elytron-oidc-client
子系统。
此流程解释了如何使用环境变量配置 elytron-oidc-client
子系统以使用 OIDC 保护应用程序。
3.5.1. JBoss EAP 中的 OpenID Connect 配置
当您使用 OpenID 供应商保护应用程序时,您不需要在本地配置任何安全域资源。elytron-oidc-client
子系统在 JBoss EAP 中提供原生 OpenID Connect (OIDC)客户端,以与 OpenID 供应商连接。JBoss EAP 根据您的 OpenID 提供程序配置自动为您的应用程序创建虚拟安全域。
将 OIDC 客户端与红帽构建的 Keycloak 搭配使用。如果可将其他 OpenID 供应商配置为使用 JSON Web 令牌(JWT)的访问令牌,并可配置为使用 RS256、RS384、RS512、ES256、ES384 或 ES512 签名算法。
要启用 OIDC 的使用,您可以配置 elytron-oidc-client
子系统或应用程序本身。JBoss EAP 激活 OIDC 身份验证,如下所示:
-
当您将应用程序部署到 JBoss EAP 时,
elytron-oidc-client
子系统会扫描部署,以检测是否需要 OIDC 身份验证机制。 -
如果子系统在
elytron-oidc-client
子系统或应用程序部署描述符中检测到部署的 OIDC 配置,JBoss EAP 为应用启用 OIDC 身份验证机制。 -
如果子系统在两个位置检测到 OIDC 配置,则
elytron-oidc-client
子系统secure-deployment
属性中的配置优先于应用程序部署描述符中的配置。
3.5.2. 创建使用 OpenID Connect 保护的应用程序
要创建一个 web 应用,请创建一个具有所需依赖项和目录结构的 Maven 项目。创建一个 Web 应用程序,其中包含一个 servlet,它将返回从登录的用户主体和属性中获取的用户名。如果没有登录的用户,servlet 将返回文本"NO AUTHENTICATED USER"。
先决条件
- 您已安装了 Maven。如需更多信息,请参阅 下载 Apache Maven。
流程
使用
mvn
命令建立一个 Maven 项目。该命令创建项目的目录结构以及pom.xml
配置文件。语法
$ mvn archetype:generate \ -DgroupId=${group-to-which-your-application-belongs} \ -DartifactId=${name-of-your-application} \ -DarchetypeGroupId=org.apache.maven.archetypes \ -DarchetypeArtifactId=maven-archetype-webapp \ -DinteractiveMode=false
Example
$ mvn archetype:generate \ -DgroupId=com.example.app \ -DartifactId=simple-webapp-example \ -DarchetypeGroupId=org.apache.maven.archetypes \ -DarchetypeArtifactId=maven-archetype-webapp \ -DinteractiveMode=false
进入到应用程序根目录:
语法
$ cd <name-of-your-application>
Example
$ cd simple-webapp-example
将生成的
pom.xml
文件的内容替换为以下文本:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example.app</groupId> <artifactId>simple-webapp-example</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>simple-webapp-example Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <version.maven.war.plugin>3.3.2</version.maven.war.plugin> <version.eap.plugin>1.0.0.Final-redhat-00014</version.eap.plugin> <version.server>8.0.0.GA-redhat-00009</version.server> <version.bom.ee>${version.server}</version.bom.ee> </properties> <repositories> <repository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga/</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga/</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.bom</groupId> <artifactId>jboss-eap-ee-with-tools</artifactId> <version>${version.bom.ee}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.wildfly.security</groupId> <artifactId>wildfly-elytron-auth-server</artifactId> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>${version.maven.war.plugin}</version> </plugin> <plugin> <groupId>org.jboss.eap.plugins</groupId> <artifactId>eap-maven-plugin</artifactId> <version>${version.eap.plugin}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> </channels> <feature-packs> <feature-pack> <location>org.jboss.eap:wildfly-ee-galleon-pack</location> </feature-pack> <feature-pack> <location>org.jboss.eap.cloud:eap-cloud-galleon-pack</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>elytron-oidc-client</layer> </layers> <galleon-options> <jboss-fork-embedded>true</jboss-fork-embedded> </galleon-options> </configuration> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
注意-
<version.eap.plugin>1.0.0.Final-redhat-00014</version.eap.plugin
> 是 JBoss EAP Maven 插件的示例版本。有关 JBoss EAP Maven 插件发行版本的更多信息,请参阅 Red Hat Maven 存储库: https://maven.repository.redhat.com/earlyaccess/all/org/jboss/eap/plugins/eap-maven-plugin/。
-
创建一个用于存储 Java 文件的目录。
语法
$ mkdir -p src/main/java/<path_based_on_artifactID>
Example
$ mkdir -p src/main/java/com/example/app
前往新目录。
语法
$ cd src/main/java/<path_based_on_artifactID>
Example
$ cd src/main/java/com/example/app
使用以下内容创建一个
securedServlet.java
文件:package com.example.app; import java.io.IOException; import java.io.PrintWriter; import java.security.Principal; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.wildfly.security.auth.server.SecurityDomain; import org.wildfly.security.auth.server.SecurityIdentity; import org.wildfly.security.authz.Attributes; import org.wildfly.security.authz.Attributes.Entry; /** * A simple secured HTTP servlet. It returns the user name and * attributes obtained from the logged-in user's Principal. If * there is no logged-in user, it returns the text * "NO AUTHENTICATED USER". */ @WebServlet("/secured") public class SecuredServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try (PrintWriter writer = resp.getWriter()) { Principal user = req.getUserPrincipal(); SecurityIdentity identity = SecurityDomain.getCurrent().getCurrentSecurityIdentity(); Attributes identityAttributes = identity.getAttributes(); Set <String> keys = identityAttributes.keySet(); String attributes = "<ul>"; for (String attr : keys) { attributes += "<li> " + attr + " : " + identityAttributes.get(attr).toString() + "</li>"; } attributes+="</ul>"; writer.println("<html>"); writer.println(" <head><title>Secured Servlet</title></head>"); writer.println(" <body>"); writer.println(" <h1>Secured Servlet</h1>"); writer.println(" <p>"); writer.print(" Current Principal '"); writer.print(user != null ? user.getName() : "NO AUTHENTICATED USER"); writer.print("'"); writer.print(user != null ? "\n" + attributes : ""); writer.println(" </p>"); writer.println(" </body>"); writer.println("</html>"); } } }
配置应用程序的
web.xml
以保护应用程序资源。Example
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" metadata-complete="false"> <security-constraint> <web-resource-collection> <web-resource-name>secured</web-resource-name> <url-pattern>/secured</url-pattern> </web-resource-collection> <auth-constraint> <role-name>Users</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>OIDC</auth-method> </login-config> <security-role> <role-name>*</role-name> </security-role> </web-app>
在本例中,只有具有角色的
用户才可以访问
应用程序。
3.5.3. 在 OpenShift 上部署应用程序
作为 JBoss EAP 应用程序开发人员,您可以在使用 OpenID Connect 子系统的 OpenShift 上部署应用程序,并将其与红帽构建的 Keycloak 服务器集成。按照以下步骤部署应用程序。
先决条件
您已在 OpenShift 中配置了带有以下配置的 Keycloak 服务器的红帽构建。如需更多信息,请参阅 红帽构建的 Keycloak Operator。
- 创建名为 JBossEAP 的域。
- 创建名为 demo 的用户。
- 为名为 demo 的用户设置密码。将 Temporary 切换到 OFF,然后单击 Set Password。在确认提示中,单击 Set password。
- 创建名为 Users 的角色。
- 将角色 用户分配给用户 demo。
- 在 Client Roles 字段中,选择您为 JBoss EAP 配置的 realm-management。
- 将角色 create-client 分配给客户端 realm-management。
流程
- 将您的应用程序代码部署到 Git 存储库。
创建包含 OIDC 配置的 secret。
使用以下内容创建名为
oidc-secret.yaml
的文件:apiVersion: v1 kind: Secret metadata: name: oidc-secret type: Opaque stringData: OIDC_PROVIDER_NAME: rh-sso OIDC_USER_NAME: demo OIDC_USER_PASSWORD: demo OIDC_SECURE_DEPLOYMENT_SECRET: mysecret
使用以下命令来创建 secret:
$ oc apply -f oidc-secret.yaml
使用以下内容创建名为
helm.yaml
的文件:build: uri: [URL TO YOUR GIT REPOSITORY] deploy: envFrom: - secretRef: name: oidc-secret
使用 JBoss EAP Helm chart 部署示例应用程序:
$ helm install eap-oidc-test-app -f helm.yaml jboss-eap/eap8
将环境变量添加到
oidc-secret.yaml
文件中,以配置 OIDC 供应商 URL 和应用程序主机名。yaml stringData: ... OIDC_HOSTNAME_HTTPS: <host of the application> OIDC_PROVIDER_URL: https://<host of the SSO provider>/realms/JBossEAP
OIDC_HOSTNAME_HTTPS
的值与以下输出对应:echo $(oc get route eap-oidc-test-app --template='{{ .spec.host }}')
OIDC_PROVIDER_URL
的值与以下输出对应:echo https://$(oc get route sso --template='{{ .spec.host }}')/realms/JBossEAP
如果没有设置
OIDC_HOSTNAME_HTTP (S)
,则会进行路由发现尝试。若要启用路由发现,OpenShift 用户必须能够列出路由资源
。例如,要创建和将routeview
角色与view
用户关联,请使用以下oc
命令:$ oc create role <role-name> --verb=list --resource=route $ oc adm policy add-role-to-user <role-name> <user-name> --role-namespace=<your namespace>
-
使用
oc apply -f oidc-secret.yaml
更新 secret。 再次部署应用程序以确保 OpenShift 使用新的环境变量:
$ oc rollout restart deploy eap-oidc-test-app
验证
在浏览器中,进入到
https://<eap-oidc-test-app route>/
。您将被重定向到红帽构建的 Keycloak 登录页面。
- 访问受保护的 servlet。
使用以下凭证登录:
username: demo password: demo
此时会出现包含主体 ID 的页面。
3.5.4. 基于环境变量的配置
使用这些环境变量在 OpenShift 镜像上配置 JBoss EAP OIDC 支持。
环境变量 | 旧的 SSO 环境变量 | 描述 | 必填 | 默认值 |
---|---|---|---|---|
OIDC_PROVIDER_NAME |
NONE.当使用 |
在使用 OIDC_PROVIDER_NAME 变量时,您必须设置为 | 是 | |
OIDC_PROVIDER_URL |
| 供应商的 URL。 | 是 | |
OIDC_USER_NAME | SSO_USERNAME | 动态客户端注册需要用户名才能接收令牌。 | 是 | |
OIDC_USER_PASSWORD | SSO_PASSWORD | 动态客户端注册需要用户密码才能接收令牌。 | 是 | |
OIDC_SECURE_DEPLOYMENT_SECRET | SSO_SECRET | secure-deployment 子系统和身份验证服务器客户端都知道。 | 否 | |
OIDC_SECURE_DEPLOYMENT_PRINCIPAL_ATTRIBUTE | SSO_PRINCIPAL_ATTRIBUTE | 配置主体名称的值。 | 否 |
典型的值: preferred_username。 |
OIDC_SECURE_DEPLOYMENT_ENABLE_CORS | SSO_ENABLE_CORS | 为单点登录应用程序启用 CORS。 | 否 |
默认值为 |
OIDC_SECURE_DEPLOYMENT_BEARER_ONLY | SSO_BEARER_ONLY | 仅接受 bearer 令牌的部署,不支持日志记录。 | 否 |
默认值为 |
OIDC_PROVIDER_SSL_REQUIRED | NONE | 默认为 external,如私有和本地地址,但不支持 https。 | 否 | 外部 |
OIDC_PROVIDER_TRUSTSTORE | SSO_TRUSTSTORE |
指定 realm | 否 | |
OIDC_PROVIDER_TRUSTSTORE_DIR | SSO_TRUSTSTORE_DIR |
查找 realm | 否 | |
OIDC_PROVIDER_TRUSTSTORE_PASSWORD | SSO_TRUSTSTORE_PASSWORD |
指定 realm | 否 | |
OIDC_PROVIDER_TRUSTSTORE_CERTIFICATE_ALIAS | SSO_TRUSTSTORE_CERTIFICATE_ALIAS |
指定 realm | 否 | |
OIDC_DISABLE_SSL_CERTIFICATE_VALIDATION | SSO_DISABLE_SSL_CERTIFICATE_VALIDATION | 与身份验证服务器交互时禁用证书验证,以注册客户端。 | 否 | |
OIDC_HOSTNAME_HTTP | HOSTNAME_HTTP | 用于非安全路由的主机名。 | 否 | 发现路由。 |
OIDC_HOSTNAME_HTTPS | HOSTNAME_HTTPS | 用于安全路由的主机名。 | 否 | 发现安全路由。 |
NONE | SSO_PUBLIC_KEY | Single Sign-On 域的公钥。使用这个选项,公钥由 OIDC 子系统自动检索。 | 否 | 如果设置,则会显示警告信息被忽略。 |