Commit 4b1a9c29 by lanmw

迈瑞单点,用saml2.0协议

parent ee07c24c
......@@ -166,6 +166,26 @@
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!--引入saml-->
<dependency>
<groupId>org.springframework.security.extensions</groupId>
<artifactId>spring-security-saml2-core</artifactId>
<version>1.0.10.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
<version>2.6.4</version>
</dependency>
<!--引入saml-->
</dependencies>
<dependencyManagement>
......@@ -203,6 +223,9 @@
<includes>
<include>*.yml</include>
<include>**/*.xml</include>
<include>*.cert</include>
<include>*.key</include>
<include>*.der</include>
</includes>
</resource>
</resources>
......
package com.keymobile.login.api;
import org.opensaml.ws.transport.http.HttpServletRequestAdapter;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
......@@ -17,7 +18,7 @@ import java.util.Map;
@RequestMapping(value = "/")
public class LoginManagement {
@RequestMapping(value = "/sessionInfo", method = {RequestMethod.POST, RequestMethod.GET})
@RequestMapping(value = "sessionInfo", method = {RequestMethod.POST, RequestMethod.GET})
public @ResponseBody Map<String,Object> verifyLogin(HttpServletRequest request, HttpServletResponse response) {
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Map<String,Object> rs = new HashMap<>();
......@@ -46,4 +47,5 @@ public class LoginManagement {
return session.getAttribute(Constants.Session_Lang).toString();
}
}
......@@ -10,28 +10,28 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
@Configuration
@ComponentScan("com.keymobile.auth.common.security")
//
//@Configuration
//@ComponentScan("com.keymobile.auth.common.security")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
// @Autowired
private CustomizedUserDetailService customUserDetailService;
@Autowired
// @Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
// @Autowired
private RESTAuthenticationFailureHandler authenticationFailureHandler;
@Autowired
// @Autowired
private RESTAuthenticationSuccessHandler authenticationSuccessHandler;
@Autowired
// @Autowired
private RESTLogoutSuccessHandler logoutSuccessHandler;
@Autowired
// @Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailService).passwordEncoder(NoOpPasswordEncoder.getInstance());
}
@Override
// @Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll();
http.csrf().disable();
......
package com.keymobile.login.saml;
import org.opensaml.common.SAMLException;
import org.opensaml.common.SAMLRuntimeException;
import org.opensaml.xml.encryption.DecryptionException;
import org.opensaml.xml.security.SecurityException;
import org.opensaml.xml.validation.ValidationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.providers.ExpiringUsernameAuthenticationToken;
import org.springframework.security.saml.SAMLAuthenticationProvider;
import org.springframework.security.saml.SAMLAuthenticationToken;
import org.springframework.security.saml.SAMLCredential;
import org.springframework.security.saml.context.SAMLMessageContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
public class CustomSAMLAuthenticationProvider extends SAMLAuthenticationProvider {
private boolean excludeCredential = false;
private static final Logger log = LoggerFactory.getLogger(SAMLAuthenticationProvider.class);
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!this.supports(authentication.getClass())) {
throw new IllegalArgumentException("Only SAMLAuthenticationToken is supported, " + authentication.getClass() + " was attempted");
} else {
SAMLAuthenticationToken token = (SAMLAuthenticationToken)authentication;
SAMLMessageContext context = token.getCredentials();
if (context == null) {
throw new AuthenticationServiceException("SAML message context is not available in the authentication token");
} else {
SAMLCredential credential;
try {
if ("urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser".equals(context.getCommunicationProfileId())) {
credential = this.consumer.processAuthenticationResponse(context);
} else {
if (!"urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser".equals(context.getCommunicationProfileId())) {
throw new SAMLException("Unsupported profile encountered in the context " + context.getCommunicationProfileId());
}
credential = this.hokConsumer.processAuthenticationResponse(context);
}
} catch (SAMLRuntimeException var11) {
log.debug("Error validating SAML message", var11);
this.samlLogger.log("AuthNResponse", "FAILURE", context, var11);
throw new AuthenticationServiceException("Error validating SAML message", var11);
} catch (SAMLException var12) {
log.debug("Error validating SAML message", var12);
this.samlLogger.log("AuthNResponse", "FAILURE", context, var12);
throw new AuthenticationServiceException("Error validating SAML message", var12);
} catch (ValidationException var13) {
log.debug("Error validating signature", var13);
this.samlLogger.log("AuthNResponse", "FAILURE", context, var13);
throw new AuthenticationServiceException("Error validating SAML message signature", var13);
} catch (SecurityException var14) {
log.debug("Error validating signature", var14);
this.samlLogger.log("AuthNResponse", "FAILURE", context, var14);
throw new AuthenticationServiceException("Error validating SAML message signature", var14);
} catch (DecryptionException var15) {
log.debug("Error decrypting SAML message", var15);
this.samlLogger.log("AuthNResponse", "FAILURE", context, var15);
throw new AuthenticationServiceException("Error decrypting SAML message", var15);
}
Object userDetails = this.getUserDetails(credential);
Object principal = this.getPrincipal(credential, userDetails);
Collection<? extends GrantedAuthority> entitlements = this.getEntitlements(credential, userDetails);
Date expiration = this.getExpirationDate(credential);
SAMLCredential authenticationCredential = this.excludeCredential ? null : credential;
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal, authenticationCredential, entitlements);
// ExpiringUsernameAuthenticationToken result = new ExpiringUsernameAuthenticationToken(expiration, principal, authenticationCredential, entitlements);
result.setDetails(userDetails);
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpSession session = request.getSession(true);
session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
this.samlLogger.log("AuthNResponse", "SUCCESS", context, result, (Exception)null);
return result;
}
}
}
}
package com.keymobile.login.saml;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
import java.util.List;
@Configuration
public class FilterCleanupConfig {
@Bean
public static BeanDefinitionRegistryPostProcessor removeUnwantedAutomaticFilterRegistration() {
return new BeanDefinitionRegistryPostProcessor() {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
final DefaultListableBeanFactory bf = (DefaultListableBeanFactory) beanFactory;
final List<String> filtersToDisable = Arrays.asList(
"samlEntryPoint", "samlFilter", "metadataDisplayFilter",
"samlWebSSOHoKProcessingFilter", "samlWebSSOProcessingFilter",
"samlLogoutProcessingFilter", "samlLogoutFilter", "metadataGeneratorFilter"
// "samlEntryPoint", "samlFilter", "samlIDPDiscovery", "metadataDisplayFilter",
// "samlWebSSOHoKProcessingFilter", "samlWebSSOProcessingFilter",
// "samlLogoutProcessingFilter", "samlLogoutFilter", "metadataGeneratorFilter"
);
Arrays.stream(beanFactory.getBeanNamesForType(javax.servlet.Filter.class))
.filter(filtersToDisable::contains)
.forEach(name -> {
BeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(FilterRegistrationBean.class)
.setScope(BeanDefinition.SCOPE_SINGLETON)
.addConstructorArgReference(name)
.addConstructorArgValue(new ServletRegistrationBean[]{})
.addPropertyValue("enabled", false)
.getBeanDefinition();
bf.registerBeanDefinition(name + "FilterRegistrationBean", definition);
});
}
};
}
}
package com.keymobile.login.saml;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.security.saml.key.JKSKeyManager;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StreamUtils;
import java.io.File;
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
public class KeystoreFactory {
private static final String FLAG_START = "-----BEGIN RSA PRIVATE KEY-----";
private static final String FLAG_END = "-----END RSA PRIVATE KEY-----";
private static final String DEFAULT_KEY_ALIAS = "defaultKeyAlias";
private static final char[] DEFAULT_KEY_STORE_PASS = "defaultKeyStorePass".toCharArray();
private static final BouncyCastleProvider BC = new BouncyCastleProvider();
/**
* 获取 JKSKeyManager。
*
* @param publicKeyCertLocation 公钥证书所在位置
* @param privateKeyCertLocation 私钥证书所在位置
* @return JKSKeyManager
*/
public JKSKeyManager getJKSKeyManager(String publicKeyCertLocation, String privateKeyCertLocation) throws Exception {
KeyStore keystore = createEmptyKeystore();
final Certificate cert = loadCert(publicKeyCertLocation);
PrivateKey privateKey = loadPrivateKey(privateKeyCertLocation);
addKeyToKeystore(keystore, cert, privateKey, DEFAULT_KEY_ALIAS, DEFAULT_KEY_STORE_PASS);
return createJKSKeyManager(keystore,
Collections.singletonMap(DEFAULT_KEY_ALIAS, new String(DEFAULT_KEY_STORE_PASS)),
DEFAULT_KEY_ALIAS);
}
/**
* 获取 JKSKeyManager
*
* @param keyStoreLocation jks 所在位置,该 jks 必须只包 1 把私钥
* @param keyStorePassword jks 的密码
* @param keyPassword 私钥的密码
* @return JKSKeyManager
*/
public JKSKeyManager getJKSKeyManager(String keyStoreLocation, char[] keyStorePassword, char[] keyPassword) throws Exception {
final File keyStoreFile = ResourceUtils.getFile(keyStoreLocation);
final KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keyStoreFile), keyStorePassword);
final Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
final String alias = aliases.nextElement();
if (ks.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
final Key key = ks.getKey(alias, keyPassword);
if (key == null) {
throw new IllegalStateException("Can't get private key in keystore with the given key password.");
}
return createJKSKeyManager(ks, Collections.singletonMap(alias, new String(keyPassword)), alias);
}
}
throw new IllegalStateException("Can't find any private key in keystore " + keyStoreLocation);
}
public void addKeyToKeystore(KeyStore keyStore, Certificate cert, PrivateKey privateKey, String alias, char[] password) throws Exception {
KeyStore.PasswordProtection pass = new KeyStore.PasswordProtection(password);
Certificate[] certificateChain = {cert};
keyStore.setEntry(alias, new KeyStore.PrivateKeyEntry(privateKey, certificateChain), pass);
}
public KeyStore createEmptyKeystore() throws Exception {
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, "".toCharArray());
return keyStore;
}
public JKSKeyManager createJKSKeyManager(KeyStore keyStore, Map<String, String> passwords, String defaultKey) {
return new JKSKeyManager(keyStore, passwords, defaultKey);
}
public Certificate loadCert(String certLocation) throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X509");
final File publicKeyCertFile = ResourceUtils.getFile(certLocation);
return cf.generateCertificate(new FileInputStream(publicKeyCertFile));
}
public PrivateKey loadPrivateKey(String privateKeyLocation) throws Exception {
final File privateKeyFile = ResourceUtils.getFile(privateKeyLocation);
byte[] keyBytes = StreamUtils.copyToByteArray(new FileInputStream(privateKeyFile));
if (privateKeyLocation.endsWith(".key")) {
final String pvKey = new String(keyBytes);
final String base64 = pvKey.replaceAll("\r", "").replaceAll("\n", "")
.replaceAll(FLAG_START, "").replaceAll(FLAG_END, "");
keyBytes = Base64.getDecoder().decode(base64);
}
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA", BC);
return keyFactory.generatePrivate(privateKeySpec);
}
}
\ No newline at end of file
package com.keymobile.login.saml;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/protected").setViewName("protected");
}
}
package com.keymobile.login.saml;
import org.opensaml.saml2.metadata.provider.MetadataProvider;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.saml.SAMLBootstrap;
import org.springframework.security.saml.context.SAMLContextProviderImpl;
import org.springframework.security.saml.context.SAMLContextProviderLB;
import org.springframework.security.saml.log.SAMLDefaultLogger;
import org.springframework.security.saml.metadata.CachingMetadataManager;
import org.springframework.security.saml.parser.ParserPoolHolder;
import org.springframework.security.saml.websso.*;
import java.util.List;
@Configuration
public class SAMLConfigDefaults {
@Bean
public static SAMLBootstrap sAMLBootstrap() {
return new SAMLBootstrap();
}
@Bean
public ParserPoolHolder parserPoolHolder() {
return new ParserPoolHolder();
}
@Bean
public SAMLContextProviderLB contextProvider() {
SAMLContextProviderLB samlContextProviderLB = new SAMLContextProviderLB();
samlContextProviderLB.setScheme("http");
samlContextProviderLB.setServerName("localhost");
samlContextProviderLB.setServerPort(8089);
samlContextProviderLB.setContextPath("/api/auth");
samlContextProviderLB.setIncludeServerPortInRequestURL(true);
return samlContextProviderLB;
}
// @Bean
// public SAMLContextProviderImpl contextProvider() {
// return new SAMLContextProviderImpl();
// }
@Bean
public SAMLDefaultLogger samlLogger() {
return new SAMLDefaultLogger();
}
@Bean
public WebSSOProfileConsumer webSSOprofileConsumer() {
return new WebSSOProfileConsumerImpl();
}
@Bean
public WebSSOProfileConsumerHoKImpl hokWebSSOprofileConsumer() {
return new WebSSOProfileConsumerHoKImpl();
}
@Bean
public WebSSOProfile webSSOprofile() {
return new WebSSOProfileImpl();
}
@Bean
public WebSSOProfileECPImpl ecpProfile() {
return new WebSSOProfileECPImpl();
}
@Bean
public WebSSOProfileHoKImpl hokWebSSOProfile() {
return new WebSSOProfileHoKImpl();
}
@Bean
public SingleLogoutProfile logoutProfile() {
return new SingleLogoutProfileImpl();
}
// 配置 IDP 元数据的 CachingMetadataManager
@Bean
public CachingMetadataManager metadataManager(List<MetadataProvider> metadataProviders) throws MetadataProviderException {
return new CachingMetadataManager(metadataProviders);
}
}
\ No newline at end of file
package com.keymobile.login.saml;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface SAMLUser {
}
\ No newline at end of file
package com.keymobile.login.saml;
import org.opensaml.saml2.core.Attribute;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.saml.SAMLCredential;
import org.springframework.security.saml.userdetails.SAMLUserDetailsService;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Default Implementation of {@link UserDetails} for Spring Boot Security SAML. This simple implementation hardly covers all security aspects since it's mostly
* hardcoded. I.E. accounts are never locked, expired, or disabled, and always return the same granted authority "ROLE_USER". Consider implementing your own
* {@link UserDetails} and {@link SAMLUserDetailsService}.
*/
public class SAMLUserDetails implements UserDetails {
private SAMLCredential samlCredential;
public SAMLUserDetails(SAMLCredential samlCredential) {
this.samlCredential = samlCredential;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
}
@Override
public String getPassword() {
return "";
}
@Override
public String getUsername() {
return samlCredential.getNameID().getValue();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
public String getAttribute(String name) {
return samlCredential.getAttributeAsString(name);
}
public String[] getAttributeArray(String name) {
return samlCredential.getAttributeAsStringArray(name);
}
public Map<String, String> getAttributes() {
return samlCredential.getAttributes().stream()
.collect(Collectors.toMap(Attribute::getName, this::getString));
}
private String getString(Attribute attribute) {
String value = getValue(attribute);
return value == null ? "" : value;
}
public Map<String, String[]> getAttributesArrays() {
return samlCredential.getAttributes().stream()
.collect(Collectors.toMap(Attribute::getName, this::getValueArray));
}
private String getValue(Attribute attribute) {
return getAttribute(attribute.getName());
}
private String[] getValueArray(Attribute attribute) {
return getAttributeArray(attribute.getName());
}
}
\ No newline at end of file
package com.keymobile.login.saml;
import com.keymobile.auth.common.security.CustomizedUserDetailService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.authentication.CachingUserDetailsService;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.saml.SAMLCredential;
import org.springframework.security.saml.userdetails.SAMLUserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Service
public class SAMLUserDetailsServiceImpl implements SAMLUserDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(SAMLUserDetailsServiceImpl.class);
@Autowired
private CustomizedUserDetailService customUserDetailService;
@Override
public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException {
LOGGER.info("Login received for user {}", credential.getNameID().getValue());
UserDetails userDetails = customUserDetailService.loadUserByUsername("root");
// HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// //根据userDetails构建新的Authentication,这里使用了
// PreAuthenticatedAuthenticationToken当然可以用其他token,如UsernamePasswordAuthenticationToken
// PreAuthenticatedAuthenticationToken authentication =
// new PreAuthenticatedAuthenticationToken(userDetails, userDetails.getPassword(),userDetails.getAuthorities());
//设置authentication中details
// UsernamePasswordAuthenticationToken authentication =
// new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
// authentication.setDetails(new WebAuthenticationDetails(request));
// //存放authentication到SecurityContextHolder
// SecurityContextHolder.getContext().setAuthentication(authentication);
// HttpSession session = request.getSession(true);
// //在session中存放security context,方便同一个session中控制用户的其他操作
// session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
//// return userDetails;
// return new SAMLUserDetails(credential);
return userDetails;
}
}
\ No newline at end of file
package com.keymobile.login.saml;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "demo.saml")
public class SamlProperties {
/**
* idp 元数据 xml 所在位置
*/
private String idpXml;
/**
* 用于验证数字签名的公钥证书所在位置,X509 格式
*/
private String publicKeyCert;
/**
* 用于数字签名的私钥所在位置,RSA 算法类型,PKCS8 格式
*/
private String privateKeyCert;
/**
* 包含用于验证数字签名的公钥证书,用于数字签名的私钥 的 JKS 所在位置
* 需要清楚传入的 JKS 中私钥的别名。
*/
private String keyStore;
/**
* {@link #keyStore} 的密码
*/
private char[] keyStorePassword;
/**
* {@link #privateKeyCert} 或 {@link #keyStore} 的私钥密码
*/
private char[] keyPassword;
public boolean useKeyStore() {
return StringUtils.isNotBlank(keyStore);
}
public boolean useCerts() {
return StringUtils.isNotBlank(publicKeyCert) && StringUtils.isNotBlank(privateKeyCert);
}
public String getIdpXml() {
return idpXml;
}
public void setIdpXml(String idpXml) {
this.idpXml = idpXml;
}
public String getPublicKeyCert() {
return publicKeyCert;
}
public void setPublicKeyCert(String publicKeyCert) {
this.publicKeyCert = publicKeyCert;
}
public String getPrivateKeyCert() {
return privateKeyCert;
}
public void setPrivateKeyCert(String privateKeyCert) {
this.privateKeyCert = privateKeyCert;
}
public String getKeyStore() {
return keyStore;
}
public void setKeyStore(String keyStore) {
this.keyStore = keyStore;
}
public char[] getKeyStorePassword() {
return keyStorePassword;
}
public void setKeyStorePassword(char[] keyStorePassword) {
this.keyStorePassword = keyStorePassword;
}
public char[] getKeyPassword() {
return keyPassword;
}
public void setKeyPassword(char[] keyPassword) {
this.keyPassword = keyPassword;
}
}
package com.keymobile.login.saml;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.saml.*;
import org.springframework.security.saml.metadata.MetadataDisplayFilter;
import org.springframework.security.saml.metadata.MetadataGeneratorFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
@ComponentScan("com.keymobile.auth.common.security")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SAMLLogoutFilter samlLogoutFilter;
@Autowired
private SAMLLogoutProcessingFilter samlLogoutProcessingFilter;
@Autowired
private MetadataDisplayFilter metadataDisplayFilter;
@Autowired
private MetadataGeneratorFilter metadataGeneratorFilter;
@Autowired
private SAMLProcessingFilter samlWebSSOProcessingFilter;
@Autowired
private SAMLWebSSOHoKProcessingFilter samlWebSSOHoKProcessingFilter;
@Autowired
private SAMLEntryPoint samlEntryPoint;
// @Autowired
// private SAMLDiscovery samlIDPDiscovery;
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void init(WebSecurity web) throws Exception {
super.init(web);
}
/**
* Defines the web based security configuration.
*
* @param http It allows configuring web based security for specific http requests.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
HttpSessionSecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository();
securityContextRepository.setSpringSecurityContextKey("SPRING_SECURITY_CONTEXT_SAML");
http
.securityContext()
.securityContextRepository(securityContextRepository);
http
.httpBasic()
.disable();
http
.csrf()
.disable();
http
.addFilterAfter(metadataGeneratorFilter, BasicAuthenticationFilter.class)
.addFilterAfter(metadataDisplayFilter, MetadataGeneratorFilter.class)
.addFilterAfter(samlEntryPoint, MetadataDisplayFilter.class)
.addFilterAfter(samlWebSSOProcessingFilter, SAMLEntryPoint.class)
.addFilterAfter(samlWebSSOHoKProcessingFilter, SAMLProcessingFilter.class)
.addFilterAfter(samlLogoutProcessingFilter, SAMLWebSSOHoKProcessingFilter.class)
// .addFilterAfter(samlIDPDiscovery, SAMLLogoutProcessingFilter.class)
.addFilterAfter(samlLogoutFilter, LogoutFilter.class);
http
.authorizeRequests()
.antMatchers("/", "/error", "/saml/**").permitAll()
// .antMatchers("/", "/error", "/saml/**", "/idpselection").permitAll()
.anyRequest().authenticated();
http
.exceptionHandling()
.authenticationEntryPoint(samlEntryPoint);
http
.logout()
.disable();
}
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return authenticationManager;
}
}
\ No newline at end of file
server:
port: 8764
port: 8082
spring:
application:
......@@ -7,15 +7,15 @@ spring:
session:
store-type: redis
redis:
namespace: test
namespace: szse
redis:
host: 139.198.127.54
port: 18072
password: dataSharing
host: localhost
port: 6379
#password: dataSharing
datasource:
url: jdbc:mysql://139.198.127.54:18073/test?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: test
password: Km@38497130
url: jdbc:mysql://localhost:3306/p0?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: dataSharing
driver-class-name: com.mysql.cj.jdbc.Driver
servlet:
multipart:
......@@ -24,12 +24,20 @@ spring:
eureka:
client:
registerWithEureka: false
registerWithEureka: true
region: default
registryFetchIntervalSeconds: 5
serviceUrl:
defaultZone: http://localhost:8081/eureka/
enabled: false
enabled: true
redirect-url:
system-management: http://localhost:8764/swagger-ui.html
\ No newline at end of file
system-management: http://localhost:8764/swagger-ui.html
demo:
saml:
idp-xml: classpath:idp-okta.xml
publickeyCert: classpath:localhost.cert
# privateKeyCert: classpath:localhost.key.der
privateKeyCert: classpath:localhost.key.der
keyPassword:
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor entityID="http://www.okta.com/exk67l5t6p2UNYn6l5d7" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"><md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIDqDCCApCgAwIBAgIGAYKxtQdnMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi05NTA5MDU0OTEcMBoGCSqGSIb3DQEJ
ARYNaW5mb0Bva3RhLmNvbTAeFw0yMjA4MTgxNjA1NDdaFw0zMjA4MTgxNjA2NDdaMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsG
A1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi05NTA5MDU0OTEc
MBoGCSqGSIb3DQEJARYNaW5mb0Bva3RhLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBALDFFJaTplxbuSYGLSp++TXBQWX9t7MHOR+INrUrxamxhH+wIfe3iJE5A3PvCEXI26abEzCi
MZjv3DTTuSLV6WLH+l11KulFo2j5vRuFFAkGeHy3diM+1z8P1jUGhEaCYvmmiXMe7aFBSNKCI7J2
LjxxI+slv7lQ/tnYcROoXxd3Y4U8KkveymXahMCW5NEKbsRY0b6ASk+CwRDAAmG/R3cn7PMLsUu+
iWZPwFwXN1bSnnaVu4a7sQi4B1SQxiySHBUhJUoi1Udicj8k6cceaoUHxRQEM/CfJiexqdyvdtfm
DdXxFN5BhzGSf8ZPC/Ewd+Ie4wLg1iVqHdnWEDl+h8kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA
huWqwM8Mgn9MHZNdbbTKKI7UqeQ7zPU4aeCoBMOSFyU+/XrlbFq4KUJvnLq8W1DQSLbxSIZbQTdT
al2aDAp3OGp/yxMN9JaMlZsVJf9QpHWX3SL0zwnr/N1lSlzP43T13a6kENhCeBjs24iBKafyH1ZG
fP6+UQxCVdYyngRKiMKRJmnNf4g5n2i27CMKk+zPTYwVMOzbDQDOTdEHU3u524XwyDDpfC2Nzoll
ZyH4lZCjfCQPwm0MCKK+TC8hXiSZ1dMVDTDQ3n+MSmJbgul6TQXX1JCLKYu3Xbj+X1DLjvHgcSa+
gucO7vek44zuQ6NlJiCBNZ8HK75ZnBfbfMe/JQ==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev-95090549.okta.com/home/dev-95090549_mairuisamldemo_1/0oa67l5t6q5hdrLNV5d7/aln67lcg0a4ZyKKiv5d7"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://dev-95090549.okta.com/home/dev-95090549_mairuisamldemo_1/0oa67l5t6q5hdrLNV5d7/aln67lcg0a4ZyKKiv5d7"/></md:IDPSSODescriptor></md:EntityDescriptor>
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIC+zCCAeOgAwIBAgIJAIU7CnmezGizMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0xNjA0MDMwMjEwMjVaFw0yNjA0MDEwMjEwMjVaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAN1NO3L/yCCb+MYFkypvJXcjlQuyRG7UFATYOYQZzIxsD9AtnXPh67uVkZTI
oK7Ps5X4a5qVARtdN+GCFZ/ITahlAlIx8rmVsbz+7XPWpGPf75tKbem3pON2NlYW
wIEQqyuValZHDUMgIXPdGIAZeNejVu7gYMLJwiSMtB0uBM69ptzgigJcbnup/cSL
W4fBh4ck5kj0SVmX58knfaizrVf+ghGyNFha9Xy+DoilCofxwFIpVskv/hczZ5L+
e81R+u2UbNzRwf8paF5fdVwaHPGLOYSBGjSm71VDdJqlvKrJCBoCQODhtmJOmDHD
jtf6gwwbdg3g9GvyqIJnRqBO908CAwEAAaNQME4wHQYDVR0OBBYEFMNtl5fAchs3
5gZS4EF8/0C7QfBQMB8GA1UdIwQYMBaAFMNtl5fAchs35gZS4EF8/0C7QfBQMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAADVL8LgYGlmaHlyrKyKfsQF
TVbdT1Fk3WaGocVbhmvFeEBHScSJNR0syDcDM1C18pZ6Jc73cW7UdtLbLbRNPXS+
qcp5GZroafndPIL2QzdKXfc5MiGH7CRCZit9kiNJ6YYgsztappXnwKblioJHB1Bc
oLRzMeD295DAGLEVuc5tSY7JHBD3YQS9Pwt3ivrvvCzFKOU9nHqChMCplO4StGpS
bbSR6XNgsPA0XLWlleuTqLGvJ4bHXPKC+0Y+0AiQYx3GeWLVrwJ4w+PFEK73vyuB
9H10x+zy1nFWvqoa+K66EA4u7DpEoHJBlqH0AVWAd8q9488DpCo1x4ujTGw7AHE=
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA3U07cv/IIJv4xgWTKm8ldyOVC7JEbtQUBNg5hBnMjGwP0C2d
c+Hru5WRlMigrs+zlfhrmpUBG1034YIVn8hNqGUCUjHyuZWxvP7tc9akY9/vm0pt
6bek43Y2VhbAgRCrK5VqVkcNQyAhc90YgBl416NW7uBgwsnCJIy0HS4Ezr2m3OCK
Alxue6n9xItbh8GHhyTmSPRJWZfnySd9qLOtV/6CEbI0WFr1fL4OiKUKh/HAUilW
yS/+FzNnkv57zVH67ZRs3NHB/yloXl91XBoc8Ys5hIEaNKbvVUN0mqW8qskIGgJA
4OG2Yk6YMcOO1/qDDBt2DeD0a/KogmdGoE73TwIDAQABAoIBAQDG0OH9+OnU0gt3
6/5A+0XPeTooHen5H7M0fwV9Nqhb56F1R+XS/D8Kcd8uqegh5RvUOjCB2if6a48O
nA3NVOjfxo+FRLZqIKBjySuPDGD4EXF0NDP26zPJ3qQGR75+tXjyWPQFuyOhELa9
Hv8p5rh4EpjBVvfXR+eRao9OP8+142Sedn5yKobQ6Qe9h4TIgBoCi1XCs86ySChr
7ITG3vEeB3Eq5hSbeN255m+VGjDySeeXsKHmnDHEq0ayLa8LbmD0XLmiLTrbV8IO
Zy7qDxxnlIxjAmmbQj42orNNhDQwoGzy1wa8Yh5/3gwdxGXhufo7ItkkeRnCKCmh
ThP0GSqBAoGBAPZNtNEHDxo5Getm4DbywTHYv+XBlWfLDkJSRjMSTCKzv9MemoX4
vE5sx4ax8oLRcz4pQnfbXQeDePvvLyWApS6qhWbS9qf8oaIt2exPolqmCJibdGpM
Y0Xk3ZFpUA7a+2jPK1PbrwLj/w7zNmFU8Rh/8RZS0QmBIcxovPH7kZ7vAoGBAOYD
jXGVxcxsTdK8Ns6hltVPEE+XmWGfInCVfpAvECN+plwna1abdXafYnMXlmg/tC4q
2Ufkcw3PEtFKCAMQ1P0n8jSKXpjj1Lxlrunj2404eH93uHJih6zYE2gb/P+7jm49
377SQOObrueWZUy4mIIZmbT6464rq6sKP6tb1i2hAoGBAIQG31f0yrmpxiUTPjj2
I21O3H6SKD488GXIqGyT8E/hvn+yte3+iSIY2VNwa6iIEZhOkZyh79opNV8GtWUK
8oBzU5Lsnt8pYpMGtPwhK8wfmBgFrH+Wdthud/6MTyfHZmCmPHl1FvkbsgsXgBzo
ZVxWqKrotbi8iZuCwVWNHl/tAoGAEms2aGIV9Mi3cqifuuw1p98s7zK0lZyopVtT
Rzh9kloR+E8vyT+pqFYbDBxXbwGq7AeCXr9sdy6d0ySaf6RZaexI+OwbpyKXZn6+
Avy8GBLtk0eC/aXmN3EWHMAhAlmCjlFmGWG80H0nBGSGuB4QGFr0dAmjMc9Nb+Ti
NFamUAECgYEA7uPN2cpwvVlt4Q4BHxjvvo1XDRe5c+RwDVa/dYkLu85HVvRd42SJ
QgIdcZR9kLRXuOFCWv1shFmfHPqfmH0q6hn39TgVnUyHxzBlAbP5Dx/n4FRs8EP8
qqNS0ft5Mqoy1UuJL6N5iDYY+i8Is90bsC9mMPj007kfFcyJcRULrSA=111
-----END RSA PRIVATE KEY-----
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment