欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 会展 > springmvc-springsecurity-redhat keycloak SAML2 xml实现

springmvc-springsecurity-redhat keycloak SAML2 xml实现

2024/10/25 12:08:44 来源:https://blog.csdn.net/GOon_star/article/details/143226281  浏览:    关键词:springmvc-springsecurity-redhat keycloak SAML2 xml实现
环境准备:

jdk17

redhat keycloak 24

spring security 6

参照文档:

红帽KeyCloak:Red Hat build of Keycloak | Red Hat Product Documentation

入门指南:入门指南 | Red Hat Product Documentation

服务器管理指南:服务器管理指南 | Red Hat Product Documentation

Redhat Keycloak:

本地启动:

\rhbk-24.0.7\bin\kc.bat start-dev --http-port 8180

管理控制台的URL:http://localhost:8180/admin

账户控制台的URL:http://localhost:8180/realms/{myrealm}/account

Spring MVC:

<mvc:redirect-view-controller path="/aml01/saml2/sso_login"
        redirect-url="/saml2/authenticate/saml-app" />

saml-app:同security中的registration-id

Spring security:

POM引入包:

<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-saml2-service-provider</artifactId>
</dependency>
	<http auto-config="true"><intercept-url pattern="/**" access="authenticated"/><saml2-loginauthentication-success-handler-ref="samlAuthenticationSuccessHandler"
/><saml2-logout /></http><relying-party-registrations><relying-party-registration registration-id="saml-app"entity-id="saml-app"assertion-consumer-service-location="http://localhost:8080/login/saml2/sso/{registrationId}"assertion-consumer-service-binding="POST"single-logout-service-location="http://localhost:8080/logout/saml2/slo"single-logout-service-response-location="http://localhost:8080/logout/saml2/slo"asserting-party-id="saml-xml"><signing-credential certificate-location="classpath:credentials/rp-certificate.crt"private-key-location="classpath:credentials/rp-private.key"/></relying-party-registration><asserting-party asserting-party-id="saml-xml"entity-id="http://localhost:8180/realms/demo"single-sign-on-service-location="http://localhost:8180/realms/demo/protocol/saml"single-sign-on-service-binding="POST"signing-algorithms="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"single-logout-service-location="http://localhost:8180/realms/demo/protocol/saml"single-logout-service-binding="POST"single-logout-service-response-location="http://localhost:8180/realms/demo/protocol/saml"want-authn-requests-signed="true"><verification-credential private-key-location="classpath:credentials/rp-private.key"certificate-location="classpath:credentials/idp-certificate.crt"/><encryption-credential private-key-location="classpath:credentials/rp-private.key"certificate-location="classpath:credentials/idp-certificate.crt"/></asserting-party></relying-party-registrations>

这个URL「assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"」和keycloak的client的Valid redirect URIs相同

Valid redirect URIs:localhost:8080/login/saml2/sso/saml-app

证明书和key做成:
openssl req -newkey rsa:2048 -nodes -keyout rp-private.key -x509 -days 365 -out rp-certificate.crt

rp-certificate.crt导入keycloak的Clients -> client details ->keys ->import key

代码:

包结构:

└─pom.xml
│  
└─src
    ├─main
    │  ├─java
    │  │  └─example
    │  │          IndexController.java
    │  │          KeyLoader.java
    │  │          WebConfiguration.java
    │  │          
    │  ├─resources
    │  │  │  logback.xml
    │  │  │  
    │  │  └─credentials
    │  │          idp-certificate.crt
    │  │          rp-certificate.crt
    │  │          rp-private.key
    │  │          
    │  └─webapp
    │      ├─META-INF
    │      │      MANIFEST.MF
    │      │      
    │      ├─resources
    │      │  ├─css
    │      │  │      bootstrap-responsive.css
    │      │  │      bootstrap.css
    │      │  │      
    │      │  └─img
    │      │          favicon.ico
    │      │          logo.png
    │      │          
    │      └─WEB-INF
    │          │  jboss-web.xml
    │          │  spring-servlet.xml
    │          │  web.xml
    │          │  
    │          ├─spring
    │          │      security.xml
    │          │      
    │          └─templates
    │                  index.html
    │                  
    └─test
        └─java

pom:

<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>org.springframework.security</groupId><artifactId>keycloak-integration-demo</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><properties><spring.version>6.2.1</spring.version> <!-- Adjust to your Spring BOM version --><junit.version>5.10.3</junit.version></properties><dependencies><!-- OpenSAML Dependencies --><dependency><groupId>org.opensaml</groupId><artifactId>opensaml-saml-api</artifactId><version>4.1.1</version></dependency><dependency><groupId>org.opensaml</groupId><artifactId>opensaml-saml-impl</artifactId><version>4.1.1</version></dependency><!-- Spring Dependencies --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>6.1.3</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-config</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-saml2-service-provider</artifactId><version>${spring.version}</version></dependency><!-- Thymeleaf Dependencies --><dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring6</artifactId><version>3.1.2.RELEASE</version></dependency><dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity6</artifactId><version>3.1.2.RELEASE</version></dependency><!-- Servlet API --><dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>6.1.0</version><scope>provided</scope></dependency><!-- Testing Dependencies --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>${junit.version}</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>${junit.version}</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>6.1.13</version><scope>test</scope></dependency><dependency><groupId>org.assertj</groupId><artifactId>assertj-core</artifactId><version>3.26.3</version><scope>test</scope></dependency><dependency><groupId>org.htmlunit</groupId><artifactId>htmlunit</artifactId><version>4.3.0</version><scope>test</scope></dependency></dependencies><build><finalName>aml-web</finalName><plugins><!-- Maven War Plugin --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>3.3.2</version></plugin><!-- Maven Surefire Plugin --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.0.0-M7</version><configuration><includes><include>**/*Tests.java</include></includes></configuration></plugin><!-- Other plugins like Gretty and Integrtest would need to be replaced with their Maven equivalents or configured differently --></plugins></build><repositories><repository><id>central</id><url>https://repo.maven.apache.org/maven2</url></repository><repository><id>spring-snapshots</id><url>https://repo.spring.io/snapshot</url><snapshots><enabled>true</enabled></snapshots></repository><repository><id>spring-milestones</id><url>https://repo.spring.io/milestone</url></repository><repository><id>shibboleth-releases</id><url>https://build.shibboleth.net/nexus/content/repositories/releases</url></repository></repositories>
</project>

security.xml:

<b:beans xmlns="http://www.springframework.org/schema/security"xmlns:b="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"><http auto-config="true"><intercept-url pattern="/**" access="authenticated"/><saml2-loginauthentication-success-handler-ref="samlAuthenticationSuccessHandler"
/><saml2-logout /></http><!-- 認証成功した場合画面遷移Handler --><b:bean id="samlAuthenticationSuccessHandler"class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler"><b:property name="targetUrlParameter" value="redirectTo" /><b:property name="alwaysUseDefaultTargetUrl" value="true" /><b:property name="defaultTargetUrl" value="/test" /></b:bean><user-service><user name="user" password="{noop}password" authorities="ROLE_USER" /></user-service><relying-party-registrations><relying-party-registration registration-id="saml-app"entity-id="saml-app"assertion-consumer-service-location="http://localhost:8080/login/saml2/sso/{registrationId}"assertion-consumer-service-binding="POST"single-logout-service-location="http://localhost:8080/logout/saml2/slo"single-logout-service-response-location="http://localhost:8080/logout/saml2/slo"asserting-party-id="saml-xml"><signing-credential certificate-location="classpath:credentials/rp-certificate.crt"private-key-location="classpath:credentials/rp-private.key"/></relying-party-registration><asserting-party asserting-party-id="saml-xml"entity-id="http://localhost:8180/realms/demo"single-sign-on-service-location="http://localhost:8180/realms/demo/protocol/saml"single-sign-on-service-binding="POST"signing-algorithms="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"single-logout-service-location="http://localhost:8180/realms/demo/protocol/saml"single-logout-service-binding="POST"single-logout-service-response-location="http://localhost:8180/realms/demo/protocol/saml"want-authn-requests-signed="true"><verification-credential private-key-location="classpath:credentials/rp-private.key"certificate-location="classpath:credentials/idp-certificate.crt"/><encryption-credential private-key-location="classpath:credentials/rp-private.key"certificate-location="classpath:credentials/idp-certificate.crt"/></asserting-party></relying-party-registrations> </b:beans>

spring-servlet.xml:

<!--~ Copyright 2022 the original author or authors.~~ Licensed under the Apache License, Version 2.0 (the "License");~ you may not use this file except in compliance with the License.~ You may obtain a copy of the License at~~      https://www.apache.org/licenses/LICENSE-2.0~~ Unless required by applicable law or agreed to in writing, software~ distributed under the License is distributed on an "AS IS" BASIS,~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.~ See the License for the specific language governing permissions and~ limitations under the License.--><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="example"/></beans>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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/javaeehttps://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"><!--- Location of the XML file that defines the root application context- Applied by ContextLoaderListener.--><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring/*.xml</param-value></context-param><filter><filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter><filter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern></filter-mapping><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><servlet><servlet-name>spring</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class></servlet><servlet-mapping><servlet-name>spring</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>

index.html:

<!--~ Copyright 2022 the original author or authors.~~ Licensed under the Apache License, Version 2.0 (the "License");~ you may not use this file except in compliance with the License.~ You may obtain a copy of the License at~~      https://www.apache.org/licenses/LICENSE-2.0~~ Unless required by applicable law or agreed to in writing, software~ distributed under the License is distributed on an "AS IS" BASIS,~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.~ See the License for the specific language governing permissions and~ limitations under the License.--><!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head><title>Spring Security - SAML 2.0 Login & Logout</title><meta charset="utf-8" /><style>span, dt {font-weight: bold;}</style><link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
</head>
<body>
<div class="container"><ul class="nav"><li class="nav-item"><form th:action="@{/logout}" method="post"><button class="btn btn-primary" id="rp_logout_button" type="submit">RP-initiated Logout</button></form></li></ul></div><main role="main" class="container"><h1 class="mt-5">SAML 2.0 Login & Single Logout with Spring Security</h1><p class="lead">You are successfully logged in as <span sec:authentication="name"></span></p><p class="lead">You're email address is <span th:text="${emailAddress}"></span></p><h2 class="mt-2">All Your Attributes</h2><dl th:each="userAttribute : ${userAttributes}"><dt th:text="${userAttribute.key}"></dt><dd th:text="${userAttribute.value}"></dd></dl><h6>Visit the <a href="https://docs.spring.io/spring-security/site/docs/current/reference/html5/#servlet-saml2" target="_blank">SAML 2.0 Login & Logout</a> documentation for more details.</h6></main>
</div>
</body>
</html>

logback.xml:

<configuration><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><logger name="org.springframework.security" level="TRACE"/><root level="TRACE"><appender-ref ref="STDOUT" /></root></configuration>

credentials:

idp-certificate.crt  keycloak的idp RSA256 cetificate

rp-certificate.crt   上面生成

rp-private.key   上面生成

WebConfiguration.java:

/** Copyright 2022 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package example;import java.util.List;import org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring6.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer, ApplicationContextAware {private ApplicationContext context;@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {AuthenticationPrincipalArgumentResolver principalArgumentResolver = new AuthenticationPrincipalArgumentResolver();principalArgumentResolver.setBeanResolver(new BeanFactoryResolver(this.context.getAutowireCapableBeanFactory()));resolvers.add(principalArgumentResolver);}@Overridepublic void setApplicationContext(ApplicationContext context) throws BeansException {this.context = context;}@Beanpublic SpringResourceTemplateResolver templateResolver() {SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();templateResolver.setApplicationContext(this.context);templateResolver.setPrefix("/WEB-INF/templates/");templateResolver.setSuffix(".html");templateResolver.setTemplateMode(TemplateMode.HTML);templateResolver.setCacheable(false);return templateResolver;}@Beanpublic SpringTemplateEngine templateEngine(SpringResourceTemplateResolver templateResolver) {SpringTemplateEngine templateEngine = new SpringTemplateEngine();templateEngine.setTemplateResolver(templateResolver);templateEngine.setEnableSpringELCompiler(true);templateEngine.addDialect(new SpringSecurityDialect());return templateEngine;}@Beanpublic ThymeleafViewResolver viewResolver(SpringTemplateEngine templateEngine) {ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();viewResolver.setTemplateEngine(templateEngine);return viewResolver;}}

IndexController.java:

/** Copyright 2022 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package example;import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;@Controller
public class IndexController {private final RelyingPartyRegistrationRepository repository;public IndexController(RelyingPartyRegistrationRepository repository) {this.repository = repository;}@GetMapping("/test")public String index(Model model, @AuthenticationPrincipal Saml2AuthenticatedPrincipal principal) {String emailAddress = principal.getFirstAttribute("email");model.addAttribute("emailAddress", emailAddress);model.addAttribute("userAttributes", principal.getAttributes());return "index";}}

访问地址:

localhost:8080/test

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com