3.6. 使用 SAML 保护应用程序


安全断言标记语言(SAML)充当数据格式和协议,支持在双方之间交换身份验证和授权信息。这两方通常包括身份提供程序和服务提供商。此信息采用包含断言的 SAML 令牌的形式。身份提供程序会发出这些 SAML 令牌,以限制这些主题与服务提供商进行身份验证。主题可将 SAML 令牌与多个服务提供商重复使用,可在 SAML v2 中启用基于浏览器的单点登录。

您可以使用 Keycloak SAML 适配器功能 pack 提供的 Galleon 层来保护 web 应用程序。

有关 Keycloak SAML 适配器功能软件包的详情,请参考 Keycloak SAML adapter 功能 pack 使用 SAML 保护应用程序

Keycloak SAML 适配器 Galleon pack 是一个 Galleon 功能软件包,其中包括 keycloak-saml 层。使用功能软件包中的 keycloak-saml 层在 JBoss EAP 中安装必要的模块和配置。如果要使用 SAML,则需要使用红帽构建的 Keycloak 作为 Single Sign-On (SSO)的身份供应商。当为 source-to-image (S2I)使用 keycloak-saml SAML 适配器 Galleon 层时,您可以选择使用 SAML 客户端功能来自动注册 Identity Service Provider (IDP),如红帽构建的 Keycloak。

Red Hat build of Keycloak 是一个身份和访问管理供应商,用于使用单点登录(SSO)保护 Web 应用程序。它支持 OpenID Connect,它是 OAuth 2.0 和 SAML 的扩展。

以下流程概述了使用 SAML 保护应用程序所需的基本步骤。如需更多信息,请参阅 红帽构建的 Keycloak 文档

先决条件

  • 具有红帽构建的 Keycloak 的管理员访问权限。
  • 红帽构建的 Keycloak 正在运行。如需更多信息,请参阅 红帽构建的 Keycloak Operator
  • 您使用 oc login 命令登录到 OpenShift。

流程

  1. 创建 Single Sign-On 域、用户和角色
  2. 使用 Java keytool 命令生成密钥和证书:

    keytool -genkeypair -alias saml-app -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -storepass password -dname "CN=saml-basic-auth,OU=EAP SAML Client,O=Red Hat EAP QE,L=MB,S=Milan,C=IT" -ext ku:c=dig,keyEncipherment -validity 365
    Copy to Clipboard Toggle word wrap
  3. 将密钥存储导入到 Java KeyStore (JKS)格式:

    keytool -importkeystore -deststorepass password -destkeystore keystore.jks -srckeystore keystore.p12 -srcstoretype PKCS12 -srcstorepass password
    Copy to Clipboard Toggle word wrap
  4. 在 OpenShift 中为密钥存储创建一个 secret:

    $ oc create secret generic saml-app-secret --from-file=keystore.jks=./keystore.jks --type=opaque
    Copy to Clipboard Toggle word wrap
注意

只有在使用自动 SAML 客户端注册功能时,才需要这些步骤。当 JBoss EAP 以 client-admin 用户身份将新的 SAML 客户端注册到 Keycloak 的红帽构建中时,JBoss EAP 必须将新 SAML 客户端的证书存储在红帽构建的 Keycloak 客户端配置中。这使得 JBoss EAP 能够保持私钥,同时将公共证书存储在红帽构建的 Keycloak 中,后者建立了一个经过身份验证的客户端,用于与红帽构建的 Keycloak 通信。

3.6.3. 创建使用 SAML 保护的应用程序

您可以使用安全断言标记语言(SAML)增强 Web 应用程序安全性。SAML 提供有效的用户身份验证和授权,以及单点登录(SSO)功能,使其成为增强 Web 应用程序的可靠选择。

先决条件

流程

  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
    Copy to Clipboard Toggle word wrap

    Example

    $ mvn archetype:generate \
    -DgroupId=com.example.app \
    -DartifactId=simple-webapp-example \
    -DarchetypeGroupId=org.apache.maven.archetypes \
    -DarchetypeArtifactId=maven-archetype-webapp \
    -DinteractiveMode=false
    Copy to Clipboard Toggle word wrap

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

    语法

    $ cd <name-of-your-application>
    Copy to Clipboard Toggle word wrap

    Example

    $ cd simple-webapp-example
    Copy to Clipboard Toggle word wrap

  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-pack>
                            <location>org.keycloak:keycloak-saml-adapter-galleon-pack</location>
                        </feature-pack>
                    </feature-packs>
                    <layers>
                        <layer>cloud-server</layer>
                        <layer>keycloak-saml</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>
    Copy to Clipboard Toggle word wrap
    注意
  4. 创建一个用于存储 Java 文件的目录。

    语法

    $ mkdir -p src/main/java/<path_based_on_artifactID>
    Copy to Clipboard Toggle word wrap

    Example

    $ mkdir -p src/main/java/com/example/app
    Copy to Clipboard Toggle word wrap

  5. 前往新目录。

    语法

    $ cd src/main/java/<path_based_on_artifactID>
    Copy to Clipboard Toggle word wrap

    Example

    $ cd src/main/java/com/example/app
    Copy to Clipboard Toggle word wrap

  6. 创建名为 SecuredServlet.java 的文件,其中包含以下设置:

    package com.example.app;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.security.Principal;
    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;
    /**
     * 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>");
            }
        }
    
    }
    Copy to Clipboard Toggle word wrap
  7. web.xml 文件创建目录结构:

    mkdir -p src/main/webapp/WEB-INF
    cd src/main/webapp/WEB-INF
    Copy to Clipboard Toggle word wrap
  8. 配置应用程序的 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>user</role-name>
            </auth-constraint>
        </security-constraint>
    
        <login-config>
            <auth-method>KEYCLOAK-SAML</auth-method>
        </login-config>
    
        <security-role>
            <role-name>user</role-name>
        </security-role>
    </web-app>
    Copy to Clipboard Toggle word wrap

    在本例中,只有具有 user 角色的用户才能访问应用。

验证

创建应用后,将其提交到远程 Git 存储库。

  1. 创建 Git 存储库,如 https://github.com/your-username/simple-webapp-example。有关远程存储库和 Git 的更多信息,请参阅 Git 入门 - 关于远程存储库
  2. 在应用程序的根目录中运行以下 Git 命令:

    git init -b main
    git add pom.xml src
    git commit -m "First commit"
    git remote add origin git@github.com:your-username/simple-webapp-example.git
    git remote -v
    git push -u origin main
    Copy to Clipboard Toggle word wrap

这些步骤将您的应用程序提交到远程存储库,使它能在线访问。

您可以使用 JBoss EAP 和单点登录(SSO) Galleon 层在 OpenShift 上构建和部署使用 SAML 保护的应用程序。

先决条件

  • 您已安装 Helm。如需更多信息,请参阅安装 Helm
  • 您已创建了 SAML 应用程序项目,并使其在 Git 存储库中访问。
  • 您已在管理 CLI 中输入以下命令来安装 JBoss EAP Helm chart 的存储库:

    $ helm repo add jboss-eap https://jbossas.github.io/eap-charts/
    Copy to Clipboard Toggle word wrap

流程

  1. 将您的应用程序代码部署到 Git 存储库。
  2. 创建包含所需环境变量的 OpenShift secret:

    apiVersion: v1
    kind: Secret
    metadata:
      name: saml-secret
    type: Opaque
    stringData:
      SSO_REALM: "saml-basic-auth"
      SSO_USERNAME: "client-admin"
      SSO_PASSWORD: "client-admin"
      SSO_SAML_CERTIFICATE_NAME: "saml-app"
      SSO_SAML_KEYSTORE: "keystore.jks"
      SSO_SAML_KEYSTORE_PASSWORD: "password"
      SSO_SAML_KEYSTORE_DIR: "/etc/sso-saml-secret-volume"
      SSO_SAML_LOGOUT_PAGE: "/simple-webapp-example"
      SSO_DISABLE_SSL_CERTIFICATE_VALIDATION: "true"
    Copy to Clipboard Toggle word wrap
  3. 将提供的 YAML 内容保存到文件中,如 saml-secret.yaml
  4. 使用以下命令应用保存的 YAML 文件:

    oc apply -f saml-secret.yaml
    Copy to Clipboard Toggle word wrap
  5. 创建名为 helm.yaml 的文件,其中包含以下设置:

    build:
      uri: [WEB ADDRESS TO YOUR GIT REPOSITORY]
    deploy:
      volumes:
        - name: saml-keystore-volume
          secret:
            secretName: saml-app-secret
      volumeMounts:
        - name: saml-keystore-volume
          mountPath: /etc/sso-saml-secret-volume
          readOnly: true
      envFrom:
        - secretRef:
            name: saml-secret
    Copy to Clipboard Toggle word wrap
    注意

    以 HTTP 格式指定 Web 地址,如 http://www.redhat.com。如果使用 maven 镜像,请按如下所示指定 Web 地址:

    build:
      uri: [WEB ADDRESS TO YOUR GIT REPOSITORY]
      env:
        - name: "MAVEN_MIRROR_URL"
          value: "http://..."
    Copy to Clipboard Toggle word wrap
  6. 使用 JBoss EAP Helm chart 部署示例应用程序:

    $ helm install saml-app -f helm.yaml jboss-eap/eap8
    Copy to Clipboard Toggle word wrap
  7. 将环境变量添加到 saml-secret.yaml 文件中,以配置 Keycloak 服务器 URL 和应用程序路由:

    stringData:
      ...
      HOSTNAME_HTTPS: <saml-app application route>
      SSO_URL: https://<host of the Keycloak server>
    Copy to Clipboard Toggle word wrap

    <saml-app 应用程序 route& gt ; 和 <host of the Keycloak server > 替换为适当的值。

    HOSTNAME_HTTPS 的值与以下输出对应:

    echo $(oc get route saml-app --template='{{ .spec.host }}')
    Copy to Clipboard Toggle word wrap

    SSO_URL 的值对应于以下输出:

    echo https://$(oc get route sso --template='{{ .spec.host }}')
    Copy to Clipboard Toggle word wrap
    注意

    如果无法使用这个命令,请使用 oc get routes 来列出可用的路由,并选择到红帽构建的 Keycloak 实例的路由。

  8. 使用 oc apply -f saml-secret.yaml 更新 secret。

验证

  1. 再次部署应用程序,以确保 OpenShift 使用新的环境变量:

    $ oc rollout restart deploy saml-app
    Copy to Clipboard Toggle word wrap
  2. 在浏览器中,导航到应用 URL。例如,https://<saml-app route>/simple-webapp-example

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

  3. 要获取 Web 地址,请使用以下命令访问安全 servlet:

    echo https://$(oc get route saml-app --template='{{ .spec.host }}')/simple-webapp-example/secured
    Copy to Clipboard Toggle word wrap
  4. 使用以下凭证登录:

    username: demo
    password: demo
    Copy to Clipboard Toggle word wrap

    此时会显示包含主体 ID 的页面。

您的应用程序现在使用 SAML 进行保护。

3.6.5. 创建 SSO 域、用户和角色

您可以在红帽构建的 Keycloak 环境中配置单点登录(SSO)域,定义用户角色并管理访问控制。这些操作可让您增强安全性并简化用户访问管理,确保简化的身份验证体验。这对优化 SSO 设置并改进用户身份验证流程至关重要。

先决条件

  • 具有红帽构建的 Keycloak 的管理员访问权限。
  • 红帽构建的 Keycloak 正在运行。

流程

  1. 使用 URL 登录红帽 Keycloak 管理控制台: https://<SSO route>/
  2. 在红帽构建的 Keycloak 中创建一个域,例如 saml-basic-auth。然后,您可以使用此域来创建所需的用户、角色和客户端。

    如需更多信息 ,请参阅创建域

  3. saml-basic-auth 域中创建一个角色。例如,用户

    如需更多信息,请参阅创建 realm 角色

  4. 创建用户。例如,demo

    如需更多信息,请参阅 创建用户

  5. 为用户创建密码。例如,demo

    确保密码不是临时密码。如需更多信息,请参阅 为用户 设置密码

  6. user 角色分配给用于登录访问的 demo 用户。

    如需更多信息,请参阅 分配角色映射

  7. 创建用户。例如,client-admin

    要在 JBoss EAP 服务器启动时在 Keycloak 服务器中创建 SAML 客户端,您可以使用 client-admin 用户,这需要额外的特权。如需更多信息,请参阅 创建用户

  8. 为用户创建密码。例如,client-admin

    确保密码不是临时密码。如需更多信息,请参阅 为用户 设置密码

  9. Client Roles 下拉列表中选择 realm-management
  10. 将角色 create-clientmanagement-clientsmanage-realm 分配给 client-admin 用户。

    如需更多信息,请参阅 分配角色映射

3.6.6. 用于配置 SAML 子系统的环境变量

您可以通过了解并使用以下变量来优化环境中 Keycloak 服务器的集成。这样可确保应用程序的无缝和安全 Keycloak 设置。

Expand
表 3.2. 环境变量
环境变量描述必填

APPLICATION_NAME

用作客户端名称的前缀,派生自部署名称。

选填

HOSTNAME_HTTP

HTTP OpenShift 路由的自定义主机名。如果没有设置,则执行路由发现。

选填

HOSTNAME_HTTPS

HTTPS OpenShift 路由的自定义主机名。如果没有设置,则执行路由发现。

选填

SSO_DISABLE_SSL_CERTIFICATE_VALIDATION

选择 truefalse 来启用或禁用 Keycloak 服务器证书验证。当 SSO 服务器生成自签名证书时,请考虑将其设置为 true

选填

SSO_PASSWORD

具有与 Keycloak 域交互的具有权限的用户的密码,并创建和注册客户端。例如,client-admin

True

SSO_REALM

用于关联应用客户端的 SSO 域。例如,saml-basic-auth

选填

SSO_SAML_CERTIFICATE_NAME

SAML 客户端密钥存储中的私钥和证书的别名。例如: saml-app

True

SSO_SAML_KEYSTORE

密钥存储文件的名称。例如,store .jks

True

SSO_SAML_KEYSTORE_DIR

包含客户端密钥存储的目录。例如: /etc/sso-saml-secret-volume

True

SSO_SAML_KEYSTORE_PASSWORD

密钥存储密码。例如,密码

True

SSO_SAML_LOGOUT_PAGE

注销页面。例如,simple-webapp-example

True

SSO_SAML_VALIDATE_SIGNATURE

指定 true 来验证签名或 false 以不验证它。默认情况下为 true。

选填

SSO_SECURITY_DOMAIN

用于保护 undertow 和 ejb 子系统的安全域的名称。默认为 keycloak

选填

SSO_TRUSTSTORE

包含服务器证书的 truststore 文件名。

选填

SSO_TRUSTSTORE_CERTIFICATE_ALIAS

truststore 中的证书别名。

选填

SSO_TRUSTSTORE_DIR

包含信任存储的目录。

选填

SSO_TRUSTSTORE_PASSWORD

truststore 和 certificate 的密码。例如,my keystorepass

选填

SSO_URL

SSO 服务器的 URL。例如,&lt ;SSO 服务器可访问的 route>

True

SSO_USERNAME

具有与 Keycloak 域交互以及创建和注册客户端的特权的用户名。例如,client-admin

True

3.6.7. JBoss EAP 服务器中的路由发现

您可以使用 JBoss EAP 服务器中的路由发现功能优化服务器的性能并简化指定命名空间中的路由配置。此功能对于提高服务器效率至关重要,以提供更顺畅的操作体验,特别是在未指定 HOSTNAME_HTTPS 变量时。

如果没有设置 HOSTNAME_HTTPS 变量,JBoss EAP 服务器会自动尝试路由发现。要启用路由发现,您必须创建所需的权限:

oc create role routeview --verb=list --resource=route -n YOUR_NAME_SPACE
oc policy add-role-to-user routeview system:serviceaccount:YOUR_NAME_SPACE:default --role-namespace=YOUR_NAME_SPACE -n YOUR_NAME_SPACE
Copy to Clipboard Toggle word wrap
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

Theme

© 2025 Red Hat