搜索

3.5. 使用 OpenID Connect 来保护 OpenShift 上的 JBoss EAP 应用程序

download PDF

使用 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"。

先决条件

流程

  1. 使用 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

  2. 进入到应用程序根目录:

    语法

    $ cd <name-of-your-application>

    Example

    $ cd simple-webapp-example

  3. 将生成的 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>
    注意
  4. 创建一个用于存储 Java 文件的目录。

    语法

    $ mkdir -p src/main/java/<path_based_on_artifactID>

    Example

    $ mkdir -p src/main/java/com/example/app

  5. 前往新目录。

    语法

    $ cd src/main/java/<path_based_on_artifactID>

    Example

    $ cd src/main/java/com/example/app

  6. 使用以下内容创建一个 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>");
            }
        }
    
    }
  7. 配置应用程序的 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

流程

  1. 将您的应用程序代码部署到 Git 存储库。
  2. 创建包含 OIDC 配置的 secret。

    1. 使用以下内容创建名为 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
    2. 使用以下命令来创建 secret:

      $ oc apply -f oidc-secret.yaml
  3. 使用以下内容创建名为 helm.yaml 的文件:

    build:
      uri: [URL TO YOUR GIT REPOSITORY]
    deploy:
      envFrom:
    	- secretRef:
        	  name: oidc-secret
  4. 使用 JBoss EAP Helm chart 部署示例应用程序:

    $ helm install eap-oidc-test-app -f helm.yaml jboss-eap/eap8
  5. 将环境变量添加到 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>
  6. 使用 oc apply -f oidc-secret.yaml 更新 secret。
  7. 再次部署应用程序以确保 OpenShift 使用新的环境变量:

    $ oc rollout restart deploy eap-oidc-test-app

验证

  1. 在浏览器中,进入到 https://<eap-oidc-test-app route>/

    您将被重定向到红帽构建的 Keycloak 登录页面。

  2. 访问受保护的 servlet。
  3. 使用以下凭证登录:

    username: demo
    password: demo

    此时会出现包含主体 ID 的页面。

3.5.4. 基于环境变量的配置

使用这些环境变量在 OpenShift 镜像上配置 JBoss EAP OIDC 支持。

表 3.1. 环境变量
环境变量旧的 SSO 环境变量描述必填默认值

OIDC_PROVIDER_NAME

NONE.当使用 SSO Passthrough 环境变量时,会在内部设置 "rh-sso" 名称。

在使用 OIDC_PROVIDER_NAME 变量时,您必须设置为 rh-sso

 

OIDC_PROVIDER_URL

$SSO_URL/realms/$SSO_REALM

供应商的 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

配置主体名称的值。

rh-sso 的默认 (ID 令牌)。

典型的值: preferred_username。

OIDC_SECURE_DEPLOYMENT_ENABLE_CORS

SSO_ENABLE_CORS

为单点登录应用程序启用 CORS。

默认值为 False

OIDC_SECURE_DEPLOYMENT_BEARER_ONLY

SSO_BEARER_ONLY

仅接受 bearer 令牌的部署,不支持日志记录。

默认值为 False

OIDC_PROVIDER_SSL_REQUIRED

NONE

默认为 external,如私有和本地地址,但不支持 https。

外部

OIDC_PROVIDER_TRUSTSTORE

SSO_TRUSTSTORE

指定 realm trustore 文件。如果没有设置,则适配器在处理 HTTPS 请求时无法使用信任管理器。

 

OIDC_PROVIDER_TRUSTSTORE_DIR

SSO_TRUSTSTORE_DIR

查找 realm truststore 的目录。如果没有设置,则适配器在处理 HTTPS 请求时无法使用信任管理器。

 

OIDC_PROVIDER_TRUSTSTORE_PASSWORD

SSO_TRUSTSTORE_PASSWORD

指定 realm truststore 密码。如果没有设置,则适配器在处理 HTTPS 请求时无法使用信任管理器。

 

OIDC_PROVIDER_TRUSTSTORE_CERTIFICATE_ALIAS

SSO_TRUSTSTORE_CERTIFICATE_ALIAS

指定 realm trustore 别名。需要与身份验证服务器交互才能注册客户端。

 

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 子系统自动检索。

如果设置,则会显示警告信息被忽略。

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.