Commit 8c8303b2 by lanmw

迈瑞oauth模式SSO

parent 2ad478d6
......@@ -28,7 +28,18 @@
<!-- <url>http://139.198.127.28:18081/repository/maven-public/</url>-->
<!-- </repository>-->
<!-- </repositories>-->
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
......@@ -66,6 +77,12 @@
<artifactId>springfox-swagger-ui</artifactId>
<version>2.2.2</version>
</dependency>
<!--引入oauth2-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<!--引入oauth2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
......@@ -167,25 +184,58 @@
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<!--引入saml-->
<dependency>
<groupId>org.springframework.security.extensions</groupId>
<artifactId>spring-security-saml2-core</artifactId>
<version>1.0.10.RELEASE</version>
<version>1.0.9.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
</exclusion>
<exclusion>
<artifactId>not-going-to-be-commons-ssl</artifactId>
<groupId>com.narupley</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
<version>2.6.4</version>
<exclusions>
<exclusion>
<artifactId>not-yet-commons-ssl</artifactId>
<groupId>ca.juliusdavies</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--引入saml-->
<!-- https://mvnrepository.com/artifact/org.apache.servicemix.bundles/org.apache.servicemix.bundles.not-yet-commons-ssl -->
<dependency>
<groupId>org.apache.servicemix.bundles</groupId>
<artifactId>org.apache.servicemix.bundles.not-yet-commons-ssl</artifactId>
<version>0.3.11_1</version>
</dependency>
</dependencies>
<dependencyManagement>
......@@ -226,6 +276,7 @@
<include>*.cert</include>
<include>*.key</include>
<include>*.der</include>
<include>*.p12</include>
</includes>
</resource>
</resources>
......
......@@ -7,10 +7,11 @@ import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan(basePackages = {"com.keymobile.login", "com.keymobile.config.logging"})
@ComponentScan(basePackages = {"com.keymobile.login", "com.keymobile.config.logging", "com.keymobile.login.saml"})
public class LoginApplication {
public static void main(String[] args) {
System.setProperty("org.apache.commons.ssl.trustStorePassword", "123456");
SpringApplication.run(LoginApplication.class, args);
}
......
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.*;
......@@ -19,8 +18,19 @@ import java.util.Map;
public class LoginManagement {
@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();
public @ResponseBody
Object verifyLogin(HttpServletRequest request, HttpServletResponse response) {
// Map<String, Object> map = new HashMap<>();
// map.put("context", SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
// return map;
UserDetails userDetails = null;
try {
userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
} catch (Exception e) {
return "redirect: http://localhost:1111/oauth/authorize?client_id=javaboy&redirect_uri=http://localhost:8089/api/auth/token&response_type=code&state=3UJF8q";
}
Map<String,Object> rs = new HashMap<>();
String userNameWithIdAttached = userDetails.getUsername();
rs.put(Constants.Session_UserName, userNameWithIdAttached.split(":")[0]);
......@@ -32,6 +42,10 @@ public class LoginManagement {
HttpSession session = request.getSession();
Object lang = session.getAttribute(Constants.Session_Lang);
Object access_token = session.getAttribute("access_token");
Object id_token = session.getAttribute("id_token");
rs.put("access_token", access_token);
rs.put("id_token", id_token);
rs.put(Constants.Session_Lang, lang != null ? lang.toString() : "cn");
return rs;
}
......@@ -47,5 +61,11 @@ public class LoginManagement {
return session.getAttribute(Constants.Session_Lang).toString();
}
@RequestMapping(value = "/token", method = {RequestMethod.POST, RequestMethod.GET})
public String token(HttpServletRequest request) {
request.getParameterNames();
return "ok";
}
}
package com.keymobile.login.oauth2;
import com.keymobile.auth.common.security.CustomizedUserDetailService;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.saml.SAMLCredential;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
public class AccessTokenInterceptor implements HandlerInterceptor {
private RestTemplate restTemplate;
private CustomizedUserDetailService userDetailService;
public AccessTokenInterceptor(RestTemplate restTemplate, CustomizedUserDetailService customizedUserDetailService) {
this.userDetailService = customizedUserDetailService;
this.restTemplate = restTemplate;
}
// 在请求处理之前,只有返回true才会执行请求
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 得到session
UserDetails userDetails = null;
try {
userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
} catch (Exception e) {
userDetails = getUserDetailByTokenInfo(request);
if (null != userDetails) {
response.sendRedirect("http://localhost:8089/center-home/menu/index");
return true;
}
response.sendRedirect("http://localhost:1111/oauth/authorize?client_id=javaboy&redirect_uri=http://localhost:8089/api/auth/token&response_type=code&state=3UJF8q");
return false;
}
return true;
}
private UserDetails getUserDetailByTokenInfo(HttpServletRequest request) {
String code = request.getParameter("code");
String state = request.getParameter("state");
UserDetails userDetails = null;
if (!StringUtils.isEmpty(code) && !StringUtils.isEmpty(state)) {
if (code != null) {
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("code", code);
map.add("client_id", "javaboy");
map.add("client_secret", "123");
map.add("redirect_uri", "http://localhost:8089/api/auth/token");
map.add("grant_type", "authorization_code");
restTemplate = new RestTemplateBuilder().basicAuthorization("javaboy", "123").build();
Map<String, String> resp = restTemplate.postForObject("http://localhost:1111/oauth/token", map, Map.class);
String access_token = resp.get("access_token");
String id_token = resp.get("id_token");
if (!StringUtils.isEmpty(id_token)) {
}
System.out.println("获取到token......" + access_token);
System.out.println("获取到id_token......" + id_token);
String username = exactUserInfoFromToken(access_token);
userDetails = userDetailService.loadUserByUsername(username);
//根据用户名username加载userDetails
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(),userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
HttpSession session = request.getSession(true);
session.setAttribute("access_token", access_token);
session.setAttribute("id_token", id_token);
session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
// HttpHeaders headers = new HttpHeaders();
// headers.add("Authorization", "Bearer " + access_token);
// HttpEntity<Object> httpEntity = new HttpEntity<>(headers);
// ResponseEntity<String> entity = restTemplate.exchange("http://localhost:8081/admin/hello", HttpMethod.GET, httpEntity, String.class);
// model.addAttribute("msg", entity.getBody());
// restTemplate.getForEntity("http://localhost:1111", Map.class).getBody();
}
}
return userDetails;
}
// 视图渲染后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
// 请求处理后,视图渲染前
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
private String exactUserInfoFromToken(String access_token) {
//暂时写死
return "root";
}
}
package com.keymobile.login.oauth2;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.keymobile.auth.common.security.CustomizedUserDetailService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor;
import org.springframework.boot.autoconfigure.security.oauth2.resource.FixedAuthoritiesExtractor;
import org.springframework.boot.autoconfigure.security.oauth2.resource.FixedPrincipalExtractor;
import org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.stereotype.Component;
import org.apache.commons.codec.binary.Base64;
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.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AdfsUserInfoTokenServices implements ResourceServerTokenServices {
protected final Logger logger = LoggerFactory.getLogger(getClass());
private final String userInfoEndpointUrl;
private CustomizedUserDetailService customizedUserDetailService;
private final String clientId;
private String tokenType = DefaultOAuth2AccessToken.BEARER_TYPE;
private AuthoritiesExtractor authoritiesExtractor = new FixedAuthoritiesExtractor();
private PrincipalExtractor principalExtractor = new FixedPrincipalExtractor();
public AdfsUserInfoTokenServices(CustomizedUserDetailService customizedUserDetailService, String userInfoEndpointUrl, String clientId) {
this.userInfoEndpointUrl = userInfoEndpointUrl;
this.clientId = clientId;
this.customizedUserDetailService = customizedUserDetailService;
}
public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}
@Override
public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException {
Map<String, Object> map = getMap(this.userInfoEndpointUrl, accessToken);
if (map.containsKey("error")) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("userinfo returned error: " + map.get("error"));
}
throw new InvalidTokenException(accessToken);
}
return extractAuthentication(map);
}
private OAuth2Authentication extractAuthentication(Map<String, Object> map) {
//adfs目前传了两个字段过来
String userNo = map.get("sub") == null ? "unknow" : (String)map.get("sub");
String userName = map.get("given_name") == null ? "unknow" : (String)map.get("given_name");
UserDetails userDetails = customizedUserDetailService.loadUserByUsername("root");
// Object principal = getPrincipal(map);
// List<GrantedAuthority> authorities = this.authoritiesExtractor
// .extractAuthorities(map);
OAuth2Request request = new OAuth2Request(null, this.clientId, null, true, null,
null, null, null, null);
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
// UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
// userDetails.get, "N/A", authorities);
// ExpiringUsernameAuthenticationToken result = new ExpiringUsernameAuthenticationToken(expiration, principal, authenticationCredential, entitlements);
token.setDetails(userDetails);
HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpSession session = httpServletRequest.getSession(true);
session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
return new OAuth2Authentication(request, token);
}
protected Object getPrincipal(Map<String, Object> map) {
Object principal = this.principalExtractor.extractPrincipal(map);
return (principal == null ? "unknown" : principal);
}
private Map<String, Object> getMap(String path, String accessToken) {
//暂时写死
Map<String, Object> rt = new HashMap<>();
rt.put("sub", "root");
rt.put("given_name", "root");
return rt;
//迈瑞的信息从token里面提取
// if (this.logger.isDebugEnabled()) {
// this.logger.debug("Getting user info from: " + path);
// }
// try {
// DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(
// accessToken);
// token.setTokenType(this.tokenType);
//
// logger.debug("Token value: " + token.getValue());
//
// String jwtBase64 = token.getValue().split("\\.")[1];
//
// logger.debug("Token: Encoded JWT: " + jwtBase64);
// org.apache.commons.codec.binary.Base64 base64 = new Base64();
// logger.debug("Decode: " + base64.decode(jwtBase64.getBytes()));
// String jwtJson = new String(base64.decode(jwtBase64.getBytes()));
// ObjectMapper mapper = new ObjectMapper();
// return mapper.readValue(jwtJson, new TypeReference<Map<String, Object>>(){});
// }
// catch (Exception ex) {
// this.logger.warn("Could not fetch user details: " + ex.getClass() + ", "
// + ex.getMessage());
// return Collections.<String, Object>singletonMap("error",
// "Could not fetch user details");
// }
}
@Override
public OAuth2AccessToken readAccessToken(String accessToken) {
return null;
}
}
package com.keymobile.login.oauth2;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.filter.OAuth2AuthenticationFailureEvent;
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
import org.springframework.security.oauth2.client.http.AccessTokenRequiredException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetailsSource;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.util.Assert;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CustomOauth2ClientAuthenticationProcessFilter extends OAuth2ClientAuthenticationProcessingFilter {
public CustomOauth2ClientAuthenticationProcessFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
setAuthenticationManager(new NoopAuthenticationManager());
setAuthenticationDetailsSource(authenticationDetailsSource);
}
public OAuth2RestOperations restTemplate;
private ResourceServerTokenServices tokenServices;
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new OAuth2AuthenticationDetailsSource();
private ApplicationEventPublisher eventPublisher;
/**
* Reference to a CheckTokenServices that can validate an OAuth2AccessToken
*
* @param tokenServices
*/
public void setTokenServices(ResourceServerTokenServices tokenServices) {
this.tokenServices = tokenServices;
}
/**
* A rest template to be used to obtain an access token.
*
* @param restTemplate a rest template
*/
public void setRestTemplate(OAuth2RestOperations restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
super.setApplicationEventPublisher(eventPublisher);
}
@Override
public void afterPropertiesSet() {
Assert.state(restTemplate != null, "Supply a rest-template");
super.afterPropertiesSet();
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
OAuth2AccessToken accessToken;
try {
accessToken = restTemplate.getAccessToken();
} catch (OAuth2Exception e) {
BadCredentialsException bad = new BadCredentialsException("Could not obtain access token", e);
publish(new OAuth2AuthenticationFailureEvent(bad));
throw bad;
}
try {
OAuth2Authentication result = tokenServices.loadAuthentication(accessToken.getValue());
if (authenticationDetailsSource!=null) {
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, accessToken.getValue());
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, accessToken.getTokenType());
result.setDetails(authenticationDetailsSource.buildDetails(request));
}
publish(new AuthenticationSuccessEvent(result));
return result;
}
catch (InvalidTokenException e) {
BadCredentialsException bad = new BadCredentialsException("Could not obtain user details from token", e);
publish(new OAuth2AuthenticationFailureEvent(bad));
throw bad;
}
}
private void publish(ApplicationEvent event) {
if (eventPublisher!=null) {
eventPublisher.publishEvent(event);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, Authentication authResult) throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, authResult);
// Nearly a no-op, but if there is a ClientTokenServices then the token will now be stored
restTemplate.getAccessToken();
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
AuthenticationException failed) throws IOException, ServletException {
if (failed instanceof AccessTokenRequiredException) {
// Need to force a redirect via the OAuth client filter, so rethrow here
throw failed;
}
else {
// If the exception is not a Spring Security exception this will result in a default error page
super.unsuccessfulAuthentication(request, response, failed);
}
}
private static class NoopAuthenticationManager implements AuthenticationManager {
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
throw new UnsupportedOperationException("No authentication should be done with this AuthenticationManager");
}
}
}
package com.keymobile.login.oauth2;
import com.keymobile.auth.common.security.CustomizedUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class LoginConfig implements WebMvcConfigurer {
/**
* 该方法用于注册拦截器
* 可注册多个拦截器,多个拦截器组成一个拦截器链
*/
@Autowired
private CustomizedUserDetailService customizedUserDetailService;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// addPathPatterns 添加路径
// excludePathPatterns 排除路径
registry.addInterceptor(new LoginInterceptor());
registry.addInterceptor(new AccessTokenInterceptor(new RestTemplate(), customizedUserDetailService));
// .addPathPatterns("/sys/*"); // 拦截sys路径下的url
// .excludePathPatterns("");
}
}
\ No newline at end of file
package com.keymobile.login.oauth2;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
// 在请求处理之前,只有返回true才会执行请求
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 得到session
String code = request.getParameter("code");
String state = request.getParameter("state");
if (!StringUtils.isEmpty(code) && !StringUtils.isEmpty(state)) {
return true;
}
UserDetails userDetails = null;
try {
userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
} catch (Exception e) {
response.sendRedirect("http://localhost:1111/oauth/authorize?client_id=javaboy&redirect_uri=http://localhost:8089/api/auth/token&response_type=code&state=3UJF8q");
return false;
}
return true;
}
// 视图渲染后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
// 请求处理后,视图渲染前
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
\ No newline at end of file
package com.keymobile.login.oauth2;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//@Component
public class MyOAuth2ClientAuthenticationProcessingFilter extends OAuth2ClientAuthenticationProcessingFilter {
public MyOAuth2ClientAuthenticationProcessingFilter() {
super("http://localhost:8082/login");
}
@Override
public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
new SimpleUrlAuthenticationSuccessHandler() {
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException, ServletException {
this.setDefaultTargetUrl("/home");
super.onAuthenticationSuccess(request, response, authentication);
}
};
}
}
package com.keymobile.login.oauth2;
import com.keymobile.auth.common.security.CustomizedUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenProviderChain;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
//@Configuration
public class Oauth2ClientConfig {
// @Bean
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext context, OAuth2ProtectedResourceDetails details) {
OAuth2RestTemplate template = new OAuth2RestTemplate(details, context);
AuthorizationCodeAccessTokenProvider authCodeProvider = new AuthorizationCodeAccessTokenProvider();
authCodeProvider.setStateMandatory(false);
AccessTokenProviderChain provider = new AccessTokenProviderChain(
Arrays.asList(authCodeProvider));
template.setAccessTokenProvider(provider);
return template;
}
/**
* 注册处理redirect uri的filter
* @param oauth2RestTemplate
* @param tokenService
* @return
*/
// @Bean
public OAuth2ClientAuthenticationProcessingFilter oauth2ClientAuthenticationProcessingFilter(
OAuth2RestTemplate oauth2RestTemplate,
AdfsUserInfoTokenServices tokenService) {
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter("http://localhost:8082/login");
filter.setRestTemplate(oauth2RestTemplate);
filter.setTokenServices(tokenService);
//设置回调成功的页面
filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler() {
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException, IOException, ServletException {
this.setDefaultTargetUrl("/home");
super.onAuthenticationSuccess(request, response, authentication);
}
});
return filter;
}
/**
* 注册check token服务
* @param details
* @return
*/
// @Bean
// public RemoteTokenServices tokenService(OAuth2ProtectedResourceDetails details) {
// RemoteTokenServices tokenService = new RemoteTokenServices();
// tokenService.setCheckTokenEndpointUrl("https://adfsforms.mindray.com/adfs/oauth2/token");
// tokenService.setClientId(details.getClientId());
// tokenService.setClientSecret(details.getClientSecret());
// return tokenService;
// }
}
package com.keymobile.login.saml;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.core.io.ClassPathResource;
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.io.InputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyStore;
......@@ -91,13 +93,17 @@ public class KeystoreFactory {
public Certificate loadCert(String certLocation) throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X509");
final File publicKeyCertFile = ResourceUtils.getFile(certLocation);
return cf.generateCertificate(new FileInputStream(publicKeyCertFile));
ClassPathResource classPathResource = new ClassPathResource(certLocation);
InputStream pathResourceInputStream = classPathResource.getInputStream();
// final File publicKeyCertFile = ResourceUtils.getFile(certLocation);
return cf.generateCertificate(pathResourceInputStream);
}
public PrivateKey loadPrivateKey(String privateKeyLocation) throws Exception {
final File privateKeyFile = ResourceUtils.getFile(privateKeyLocation);
byte[] keyBytes = StreamUtils.copyToByteArray(new FileInputStream(privateKeyFile));
// final File privateKeyFile = ResourceUtils.getFile(privateKeyLocation);
ClassPathResource classPathResource = new ClassPathResource(privateKeyLocation);
InputStream pathResourceInputStream = classPathResource.getInputStream();
byte[] keyBytes = StreamUtils.copyToByteArray(pathResourceInputStream);
if (privateKeyLocation.endsWith(".key")) {
final String pvKey = new String(keyBytes);
......
......@@ -3,6 +3,7 @@ package com.keymobile.login.saml;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.app.VelocityEngine;
import org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider;
......@@ -14,13 +15,16 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.saml.*;
import org.springframework.security.saml.context.SAMLContextProviderImpl;
import org.springframework.security.saml.context.SAMLContextProviderLB;
import org.springframework.security.saml.key.EmptyKeyManager;
import org.springframework.security.saml.key.KeyManager;
import org.springframework.security.saml.metadata.*;
import org.springframework.security.saml.processor.*;
......@@ -33,9 +37,11 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationFa
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
......@@ -161,21 +167,23 @@ public class SAMLConfig {
}
try {
final File file = ResourceUtils.getFile(samlProperties.getIdpXml());
Resource idpResource = new FilesystemResource(file.getPath());
ClassPathResource classPathResource = new ClassPathResource(samlProperties.getIdpXml());
InputStream pathResourceInputStream = classPathResource.getInputStream();
File templateFile = new File(samlProperties.getIdpXml());
FileUtils.copyToFile(pathResourceInputStream, templateFile);
Resource idpResource = new FilesystemResource(templateFile.getPath());
Timer refreshTimer = new Timer(true);
ResourceBackedMetadataProvider delegate;
delegate = new ResourceBackedMetadataProvider(refreshTimer, idpResource);
delegate.setParserPool(parserPool());
ExtendedMetadata extendedMetadata = extendedMetadata().clone();
ExtendedMetadataDelegate provider = new ExtendedMetadataDelegate(delegate, extendedMetadata);
provider.setMetadataTrustCheck(true);
provider.setMetadataTrustCheck(false);
provider.setMetadataRequireSignature(false);
String idpName = file.getName().replaceAll(".xml", "");
extendedMetadata.setAlias(idpName);
// String idpName = file.getName().replaceAll(".xml", "");
// extendedMetadata.setAlias(idpName);
// 配置 IDP 元数据的 provider
LOGGER.info("Loaded Idp Metadata bean {}: {}", idpName, file.getPath());
// LOGGER.info("Loaded Idp Metadata bean {}: {}", idpName, file.getPath());
return provider;
} catch (Exception e) {
throw new IllegalStateException("Unable to initialize IDP Metadata", e);
......@@ -200,11 +208,13 @@ public class SAMLConfig {
MetadataGenerator generator = new MetadataGenerator();
// generator.setEntityId("localhost-demo");
// SP 标识
generator.setEntityId("lanminwu:mairui:saml:demo");
generator.setEntityId(samlProperties.getEntityId());
generator.setExtendedMetadata(extendedMetadata());
// 如果为true,则生成的元数据将包含扩展名,指示其能够使用来自IDP发现服务的响应。
generator.setIncludeDiscoveryExtension(false);
generator.setKeyManager(keyManager);
generator.setRequestSigned(samlProperties.getSignMetadata());
generator.setWantAssertionSigned(samlProperties.getWantAssertionSigned());
if (samlProperties.getUseLB()) {
String schema = samlProperties.getContext().getSchema();
String ip = samlProperties.getContext().getServerName();
......@@ -303,9 +313,9 @@ public class SAMLConfig {
} catch (Exception e) {
throw new IllegalStateException("Unable to initialize KeyManager with keyStore: " + samlProperties.getKeyStore(), e);
}
} else {
return new EmptyKeyManager();
}
LOGGER.debug("Can't find demo.saml.key-store and demo.saml.key-alias.");
throw new IllegalArgumentException("Unable to initialize KeyManager because no parameters available.");
}
@Bean
......
......@@ -30,17 +30,6 @@ public class SAMLConfigDefaults {
@Autowired
private SamlProperties samlProperties;
// @Bean
// public SAMLContextProviderLB contextProvider() {
// SAMLContextProviderLB samlContextProviderLB = new SAMLContextProviderLB();
// samlContextProviderLB.setScheme(samlProperties.getContext().getSchema());
// samlContextProviderLB.setServerName(samlProperties.getContext().getServerName());
// samlContextProviderLB.setContextPath(samlProperties.getContext().getContextPath());
// samlContextProviderLB.setServerPort(samlProperties.getContext().getServerPort());
// samlContextProviderLB.setIncludeServerPortInRequestURL(true);
// return samlContextProviderLB;
// }
@Bean
public SAMLContextProviderImpl contextProvider() {
if (samlProperties.getUseLB()) {
......@@ -56,22 +45,6 @@ public class SAMLConfigDefaults {
}
}
// @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();
......
package com.keymobile.login.saml;
import org.apache.commons.lang3.StringUtils;
import org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider;
import org.opensaml.util.resource.FilesystemResource;
import org.opensaml.util.resource.Resource;
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.key.EmptyKeyManager;
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;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.velocity.app.VelocityEngine;
import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider;
import org.opensaml.saml2.metadata.provider.MetadataProvider;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.opensaml.xml.parse.ParserPool;
import org.opensaml.xml.parse.StaticBasicParserPool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.saml.SAMLAuthenticationProvider;
import org.springframework.security.saml.SAMLBootstrap;
import org.springframework.security.saml.SAMLDiscovery;
import org.springframework.security.saml.SAMLEntryPoint;
import org.springframework.security.saml.SAMLLogoutFilter;
import org.springframework.security.saml.SAMLLogoutProcessingFilter;
import org.springframework.security.saml.SAMLProcessingFilter;
import org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter;
import org.springframework.security.saml.context.SAMLContextProviderImpl;
import org.springframework.security.saml.key.JKSKeyManager;
import org.springframework.security.saml.key.KeyManager;
import org.springframework.security.saml.log.SAMLDefaultLogger;
import org.springframework.security.saml.metadata.CachingMetadataManager;
import org.springframework.security.saml.metadata.ExtendedMetadata;
import org.springframework.security.saml.metadata.ExtendedMetadataDelegate;
import org.springframework.security.saml.metadata.MetadataDisplayFilter;
import org.springframework.security.saml.metadata.MetadataGenerator;
import org.springframework.security.saml.metadata.MetadataGeneratorFilter;
import org.springframework.security.saml.parser.ParserPoolHolder;
import org.springframework.security.saml.processor.HTTPArtifactBinding;
import org.springframework.security.saml.processor.HTTPPAOS11Binding;
import org.springframework.security.saml.processor.HTTPPostBinding;
import org.springframework.security.saml.processor.HTTPRedirectDeflateBinding;
import org.springframework.security.saml.processor.HTTPSOAP11Binding;
import org.springframework.security.saml.processor.SAMLBinding;
import org.springframework.security.saml.processor.SAMLProcessorImpl;
import org.springframework.security.saml.util.VelocityFactory;
import org.springframework.security.saml.websso.ArtifactResolutionProfile;
import org.springframework.security.saml.websso.ArtifactResolutionProfileImpl;
import org.springframework.security.saml.websso.SingleLogoutProfile;
import org.springframework.security.saml.websso.SingleLogoutProfileImpl;
import org.springframework.security.saml.websso.WebSSOProfile;
import org.springframework.security.saml.websso.WebSSOProfileConsumer;
import org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl;
import org.springframework.security.saml.websso.WebSSOProfileConsumerImpl;
import org.springframework.security.saml.websso.WebSSOProfileECPImpl;
import org.springframework.security.saml.websso.WebSSOProfileImpl;
import org.springframework.security.saml.websso.WebSSOProfileOptions;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.ResourceUtils;
//@Configuration
//@EnableWebSecurity
//@EnableGlobalMethodSecurity(securedEnabled = true)
//@ComponentScan("com.keymobile.auth.common.security")
public class SPWebSecurityConfig extends WebSecurityConfigurerAdapter implements InitializingBean, DisposableBean {
@javax.annotation.Resource
private SpConfig spConfig;
private Timer backgroundTaskTimer;
private MultiThreadedHttpConnectionManager multiThreadedHttpConnectionManager;
public void init() {
this.backgroundTaskTimer = new Timer(true);
this.multiThreadedHttpConnectionManager = new MultiThreadedHttpConnectionManager();
}
public void shutdown() {
this.backgroundTaskTimer.purge();
this.backgroundTaskTimer.cancel();
this.multiThreadedHttpConnectionManager.shutdown();
}
@javax.annotation.Resource
private SAMLUserDetailsServiceImpl samlUserDetailsServiceImpl;
// Initialization of the velocity engine
@Bean
public VelocityEngine velocityEngine() {
return VelocityFactory.getEngine();
}
// XML parser pool needed for OpenSAML parsing
@Bean(initMethod = "initialize")
public StaticBasicParserPool parserPool() {
return new StaticBasicParserPool();
}
@Bean(name = "parserPoolHolder")
public ParserPoolHolder parserPoolHolder() {
return new ParserPoolHolder();
}
// Bindings, encoders and decoders used for creating and parsing messages
@Bean
public HttpClient httpClient() {
return new HttpClient(this.multiThreadedHttpConnectionManager);
}
// SAML Authentication Provider responsible for validating of received SAML
// messages
@Bean
public SAMLAuthenticationProvider samlAuthenticationProvider() {
SAMLAuthenticationProvider samlAuthenticationProvider = new SAMLAuthenticationProvider();
samlAuthenticationProvider.setUserDetails(samlUserDetailsServiceImpl);
samlAuthenticationProvider.setForcePrincipalAsString(false);
return samlAuthenticationProvider;
}
// Provider of default SAML Context
@Bean
public SAMLContextProviderImpl contextProvider() {
return new SAMLContextProviderImpl();
}
// Initialization of OpenSAML library
@Bean
public static SAMLBootstrap sAMLBootstrap() {
return new SAMLBootstrap();
}
// Logger for SAML messages and events
@Bean
public SAMLDefaultLogger samlLogger() {
return new SAMLDefaultLogger();
}
// SAML 2.0 WebSSO Assertion Consumer
@Bean
public WebSSOProfileConsumer webSSOprofileConsumer() {
return new WebSSOProfileConsumerImpl();
}
// SAML 2.0 Holder-of-Key WebSSO Assertion Consumer
@Bean
public WebSSOProfileConsumerHoKImpl hokWebSSOprofileConsumer() {
return new WebSSOProfileConsumerHoKImpl();
}
// SAML 2.0 Web SSO profile
@Bean
public WebSSOProfile webSSOprofile() {
return new WebSSOProfileImpl();
}
// SAML 2.0 Holder-of-Key Web SSO profile
@Bean
public WebSSOProfileConsumerHoKImpl hokWebSSOProfile() {
return new WebSSOProfileConsumerHoKImpl();
}
// SAML 2.0 ECP profile
@Bean
public WebSSOProfileECPImpl ecpprofile() {
return new WebSSOProfileECPImpl();
}
@Bean
public SingleLogoutProfile logoutprofile() {
return new SingleLogoutProfileImpl();
}
// sp密钥库
// Central storage of cryptographic keys
// @Bean
// public KeyManager keyManager(KeystoreFactory keystoreFactory) {
// return new EmptyKeyManager();
// }
@Autowired
private SamlProperties samlProperties;
@Bean
public KeystoreFactory keystoreFactory() {
return new KeystoreFactory();
}
@Bean
public KeyManager keyManager(KeystoreFactory keystoreFactory) throws Exception {
if (samlProperties.useCerts()) {
return keystoreFactory.getJKSKeyManager(samlProperties.getPublicKeyCert(), samlProperties.getPrivateKeyCert());
}
if (samlProperties.useKeyStore()) {
try {
return keystoreFactory.getJKSKeyManager(samlProperties.getKeyStore(), samlProperties.getKeyStorePassword(),
samlProperties.getKeyPassword());
} catch (Exception e) {
throw new IllegalStateException("Unable to initialize KeyManager with keyStore: " + samlProperties.getKeyStore(), e);
}
} else {
return new EmptyKeyManager();
}
}
@Bean
public WebSSOProfileOptions defaultWebSSOProfileOptions() {
WebSSOProfileOptions webSSOProfileOptions = new WebSSOProfileOptions();
webSSOProfileOptions.setIncludeScoping(false);
return webSSOProfileOptions;
}
// Entry point to initialize authentication, default values taken from
// properties file
@Bean
public SAMLEntryPoint samlEntryPoint() {
SAMLEntryPoint samlEntryPoint = new SAMLEntryPoint();
samlEntryPoint.setDefaultProfileOptions(defaultWebSSOProfileOptions());
return samlEntryPoint;
}
// 扩展元数据
// Setup advanced info about metadata
@Bean
public ExtendedMetadata extendedMetadata() {
ExtendedMetadata extendedMetadata = new ExtendedMetadata();
extendedMetadata.setIdpDiscoveryEnabled(spConfig.getIdpDiscoveryEnable());
extendedMetadata.setSigningAlgorithm(spConfig.getSignAlg());
extendedMetadata.setSignMetadata(spConfig.getSignMetadata());
extendedMetadata.setEcpEnabled(true);
return extendedMetadata;
}
// 服务发现页面地址
// IDP Discovery Service
// @Bean
// public SAMLDiscovery samlIDPDiscovery() {
// SAMLDiscovery idpDiscovery = new SAMLDiscovery();
// idpDiscovery.setIdpSelectionPath(spConfig.getIdpSelectionPath());
// return idpDiscovery;
// }
// @Bean
// @Qualifier("idp-ssocircle")
// public ExtendedMetadataDelegate ssoCircleExtendedMetadataProvider()
// throws Exception {
// final File file = ResourceUtils.getFile("classpath:idp-okta.xml");
// org.opensaml.util.resource.Resource idpResource = new FilesystemResource(file.getPath());
// Timer refreshTimer = new Timer(true);
// ResourceBackedMetadataProvider delegate;
// delegate = new ResourceBackedMetadataProvider(refreshTimer, idpResource);
// ExtendedMetadataDelegate extendedMetadataDelegate =
// new ExtendedMetadataDelegate(delegate, extendedMetadata());
// extendedMetadataDelegate.setMetadataTrustCheck(false);
// extendedMetadataDelegate.setMetadataRequireSignature(false);
// backgroundTaskTimer.purge();
// return extendedMetadataDelegate;
// }
@Bean
@Qualifier("idp-ssocircle")
public ExtendedMetadataDelegate ssoCircleExtendedMetadataProvider() {
try {
final File file = ResourceUtils.getFile("classpath:idp-mairui.xml");
Resource idpResource = new FilesystemResource(file.getPath());
Timer refreshTimer = new Timer(true);
ResourceBackedMetadataProvider delegate;
delegate = new ResourceBackedMetadataProvider(refreshTimer, idpResource);
delegate.setParserPool(parserPool());
ExtendedMetadata extendedMetadata = extendedMetadata().clone();
ExtendedMetadataDelegate provider = new ExtendedMetadataDelegate(delegate, extendedMetadata);
provider.setMetadataTrustCheck(true);
provider.setMetadataRequireSignature(false);
String idpName = file.getName().replaceAll(".xml", "");
extendedMetadata.setAlias(idpName);
// 配置 IDP 元数据的 provider
return provider;
} catch (Exception e) {
throw new IllegalStateException("Unable to initialize IDP Metadata", e);
}
}
// IDP Metadata configuration - paths to metadata of IDPs in circle of trust
// is here
// Do no forget to call iniitalize method on providers
@Bean
@Qualifier("metadata")
public CachingMetadataManager metadata() throws Exception {
List<MetadataProvider> providers = new ArrayList<MetadataProvider>();
providers.add(ssoCircleExtendedMetadataProvider());
return new CachingMetadataManager(providers);
}
// 元数据生成bean
// Filter automatically generates default SP metadata
@Bean
public MetadataGenerator metadataGenerator() throws Exception {
MetadataGenerator metadataGenerator = new MetadataGenerator();
metadataGenerator.setEntityId(spConfig.getEntityId());
metadataGenerator.setExtendedMetadata(extendedMetadata());
metadataGenerator.setIncludeDiscoveryExtension(false);
metadataGenerator.setKeyManager(keyManager(new KeystoreFactory()));
metadataGenerator.setRequestSigned(false);
metadataGenerator.setWantAssertionSigned(spConfig.getWantAssertionSigned());
return metadataGenerator;
}
// The filter is waiting for connections on URL suffixed with filterSuffix
// and presents SP metadata there
@Bean
public MetadataDisplayFilter metadataDisplayFilter() {
return new MetadataDisplayFilter();
}
// 设置登陆成功后的重定向地址,或者说是首页地址
// Handler deciding where to redirect user after successful login
@Bean
public SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler() {
SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler =
new SavedRequestAwareAuthenticationSuccessHandler();
successRedirectHandler.setDefaultTargetUrl(spConfig.getSuccessLoginUrl());
return successRedirectHandler;
}
// Handler deciding where to redirect user after failed login
@Bean
public SimpleUrlAuthenticationFailureHandler authenticationFailureHandler() {
SimpleUrlAuthenticationFailureHandler failureHandler =
new SimpleUrlAuthenticationFailureHandler();
failureHandler.setUseForward(true);
failureHandler.setDefaultFailureUrl(spConfig.getFailLoginUrl());
return failureHandler;
}
@Bean
public SAMLWebSSOHoKProcessingFilter samlWebSSOHoKProcessingFilter() throws Exception {
SAMLWebSSOHoKProcessingFilter samlWebSSOHoKProcessingFilter = new SAMLWebSSOHoKProcessingFilter();
samlWebSSOHoKProcessingFilter.setAuthenticationSuccessHandler(successRedirectHandler());
samlWebSSOHoKProcessingFilter.setAuthenticationManager(authenticationManager());
samlWebSSOHoKProcessingFilter.setAuthenticationFailureHandler(authenticationFailureHandler());
return samlWebSSOHoKProcessingFilter;
}
// Processing filter for WebSSO profile messages
@Bean
public SAMLProcessingFilter samlWebSSOProcessingFilter() throws Exception {
SAMLProcessingFilter samlWebSSOProcessingFilter = new SAMLProcessingFilter();
samlWebSSOProcessingFilter.setAuthenticationManager(authenticationManager());
samlWebSSOProcessingFilter.setAuthenticationSuccessHandler(successRedirectHandler());
samlWebSSOProcessingFilter.setAuthenticationFailureHandler(authenticationFailureHandler());
return samlWebSSOProcessingFilter;
}
@Bean
public MetadataGeneratorFilter metadataGeneratorFilter() throws Exception {
return new MetadataGeneratorFilter(metadataGenerator());
}
// Handler for successful logout
@Bean
public SimpleUrlLogoutSuccessHandler successLogoutHandler() {
SimpleUrlLogoutSuccessHandler successLogoutHandler = new SimpleUrlLogoutSuccessHandler();
successLogoutHandler.setDefaultTargetUrl(spConfig.getSuccessLogoutUrl());
return successLogoutHandler;
}
// Logout handler terminating local session
@Bean
public SecurityContextLogoutHandler logoutHandler() {
SecurityContextLogoutHandler logoutHandler =
new SecurityContextLogoutHandler();
logoutHandler.setInvalidateHttpSession(true);
logoutHandler.setClearAuthentication(true);
return logoutHandler;
}
// Filter processing incoming logout messages
// First argument determines URL user will be redirected to after successful
// global logout
@Bean
public SAMLLogoutProcessingFilter samlLogoutProcessingFilter() {
return new SAMLLogoutProcessingFilter(successLogoutHandler(),
logoutHandler());
}
// Overrides default logout processing filter with the one processing SAML
// messages
@Bean
public SAMLLogoutFilter samlLogoutFilter() {
return new SAMLLogoutFilter(successLogoutHandler(),
new LogoutHandler[]{logoutHandler()},
new LogoutHandler[]{logoutHandler()});
}
// Bindings
private ArtifactResolutionProfile artifactResolutionProfile() {
final ArtifactResolutionProfileImpl artifactResolutionProfile =
new ArtifactResolutionProfileImpl(httpClient());
artifactResolutionProfile.setProcessor(new SAMLProcessorImpl(soapBinding()));
return artifactResolutionProfile;
}
@Bean
public HTTPArtifactBinding artifactBinding(ParserPool parserPool, VelocityEngine velocityEngine) {
return new HTTPArtifactBinding(parserPool, velocityEngine, artifactResolutionProfile());
}
@Bean
public HTTPSOAP11Binding soapBinding() {
return new HTTPSOAP11Binding(parserPool());
}
@Bean
public HTTPPostBinding httpPostBinding() {
return new HTTPPostBinding(parserPool(), velocityEngine());
}
@Bean
public HTTPRedirectDeflateBinding httpRedirectDeflateBinding() {
return new HTTPRedirectDeflateBinding(parserPool());
}
@Bean
public HTTPSOAP11Binding httpSOAP11Binding() {
return new HTTPSOAP11Binding(parserPool());
}
@Bean
public HTTPPAOS11Binding httpPAOS11Binding() {
return new HTTPPAOS11Binding(parserPool());
}
// Processor
@Bean
public SAMLProcessorImpl processor() {
Collection<SAMLBinding> bindings = new ArrayList<SAMLBinding>();
bindings.add(httpRedirectDeflateBinding());
bindings.add(httpPostBinding());
bindings.add(artifactBinding(parserPool(), velocityEngine()));
bindings.add(httpSOAP11Binding());
bindings.add(httpPAOS11Binding());
return new SAMLProcessorImpl(bindings);
}
/**
* Define the security filter chain in order to support SSO Auth by using SAML 2.0
*
* @return Filter chain proxy
* @throws Exception
*/
@Bean
public FilterChainProxy samlFilter() throws Exception {
List<SecurityFilterChain> chains = new ArrayList<SecurityFilterChain>();
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"),
samlEntryPoint()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/logout/**"),
samlLogoutFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"),
metadataDisplayFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSO/**"),
samlWebSSOProcessingFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSOHoK/**"),
samlWebSSOHoKProcessingFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SingleLogout/**"),
samlLogoutProcessingFilter()));
// chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/discovery/**"),
// samlIDPDiscovery()));
return new FilterChainProxy(chains);
}
/**
* Returns the authentication manager currently used by Spring.
* It represents a bean definition with the aim allow wiring from
* other classes performing the Inversion of Control (IoC).
*
* @throws Exception
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* Defines the web based security configuration.
*
* @param http It allows configuring web based security for specific http requests.
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.authenticationEntryPoint(samlEntryPoint());
http
.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class)
.addFilterAfter(samlFilter(), BasicAuthenticationFilter.class)
.addFilterBefore(samlFilter(), CsrfFilter.class);
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/saml/**").permitAll()
.antMatchers("/css/**").permitAll()
.antMatchers("/img/**").permitAll()
.antMatchers("/js/**").permitAll()
.anyRequest().authenticated();
http
.logout()
.disable(); // The logout procedure is already handled by SAML filters.
}
/**
* Sets a custom authentication provider.
*
* @param auth SecurityBuilder used to create an AuthenticationManager.
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(samlAuthenticationProvider());
}
@Override
public void afterPropertiesSet() throws Exception {
init();
}
@Override
public void destroy() throws Exception {
shutdown();
}
}
......@@ -4,8 +4,10 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "demo.saml")
@Component
public class SamlProperties {
/**
......@@ -47,6 +49,36 @@ public class SamlProperties {
private Boolean useLB;
private String entityId;
private Boolean wantAssertionSigned;
private Boolean signMetadata;
public Boolean getWantAssertionSigned() {
return wantAssertionSigned;
}
public void setWantAssertionSigned(Boolean wantAssertionSigned) {
this.wantAssertionSigned = wantAssertionSigned;
}
public Boolean getSignMetadata() {
return signMetadata;
}
public void setSignMetadata(Boolean signMetadata) {
this.signMetadata = signMetadata;
}
public void setEntityId(String entityId) {
this.entityId = entityId;
}
public String getEntityId() {
return entityId;
}
public void setUseLB(Boolean useLB) {
this.useLB = useLB;
}
......
package com.keymobile.login.saml;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "sp")
public class SpConfig {
private String idpMetadataUrl;
private String entityId;
private Boolean wantAssertionSigned;
private Boolean signMetadata;
private String signAlg;
private Boolean idpDiscoveryEnable;
private String IdpSelectionPath;
private String successLoginUrl;
private String failLoginUrl;
private String successLogoutUrl;
private JKS jks;
@Data
public class JKS {
private String path;
private String password;
private String defaultKey;
}
}
\ No newline at end of file
......@@ -16,10 +16,10 @@ 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")
//@Configuration
//@EnableWebSecurity
//@EnableGlobalMethodSecurity(securedEnabled = true)
//@ComponentScan("com.keymobile.auth.common.security")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
......@@ -43,9 +43,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SAMLEntryPoint samlEntryPoint;
// @Autowired
// private SAMLDiscovery samlIDPDiscovery;
@Autowired
private AuthenticationManager authenticationManager;
......
server:
port: 8082
# ssl:
# key-store: classpath:javaboy.p12
# key-alias: tomcathttps
# key-store-password: 123456
# context-path: auth
spring:
......@@ -22,6 +26,20 @@ spring:
multipart:
max-file-size: 100Mb
max-request-size: 100Mb
# security:
# oauth2:
# client:
# registration:
# mairay:
# provider: mairay
# client-id: cfe5edd2-c5cb-422b-86e3-adf50d42d9e6
# authorization-grant-type: authorization_code
# redirect-uri-template: http://my-redirect-uri.com
# provider:
# mairay:
# authorization-uri: https://adfsforms.mindray.com/adfs/oauth2/authorize
# token-uri: https://adfsforms.mindray.com/adfs/oauth2/token
# user-info-uri: https://adfsforms.mindray.com/adfs/oauth2/token
eureka:
client:
......@@ -35,15 +53,25 @@ eureka:
redirect-url:
system-management: http://localhost:8764/swagger-ui.html
#80600793 H?hVm0jn
#80600745 Wenhua@015
demo:
saml:
idp-xml: classpath:idp-okta.xml
publickeyCert: classpath:localhost.cert
# privateKeyCert: classpath:localhost.key.der
privateKeyCert: classpath:localhost.key.der
idp-xml: idp-mairui.xml
# idp-xml: idp-okta.xml
entityId: https://localhost:8082
# entityId: lanminwu:mairui:saml:demo
# 是否签名断言,则需要在idp上传sp的证书/公钥文件以供解密
wantAssertionSigned: false
# 是否签名元数据
signMetadata: false
#publickeyCert: classpath:localhost.cert
#privateKeyCert: classpath:localhost.key.der
publickeyCert: localhost.cert
privateKeyCert: localhost.key.der
keyPassword:
successTargetUrl: http://localhost:8089/center-home/menu/index
useLB: true
useLB: false
context:
provider:
schema: http
......@@ -53,5 +81,68 @@ demo:
sp:
# 认证中心服务信息 -> IDP元数据URL
idpMetadataUrl: http://localhost:8080/gc-starter-ac/idp/metadata
# entityId,服务提供商唯一标识
entityId: https://localhost:8082
# 是否签名断言,则需要在idp上传sp的证书/公钥文件以供解密
wantAssertionSigned: false
# 是否签名元数据
signMetadata: false
# 签名算法
signAlg: http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
# 是否启用服务发现。一个sp可以配置多个idp,启动服务发现允许进入idp选择页面选择idp,如果不启用的话默认使用idp列表的第一个
idpDiscoveryEnable: false
# 服务发现选择页面路由
IdpSelectionPath: /saml/discovery
# idp登录成功后的重定向的页面路由,也就是首页路由
successLoginUrl: http://localhost:8089/center-home/menu/index
# idp登录失败后的重定向的页面路由
failLoginUrl: /error
# 登出成功后跳转的页面路由
successLogoutUrl: /
# 密钥库设置
jks:
# jks文件位置
path: classpath:/saml/samlKeystore.jks
# jks密码
password: nalle123
# 私钥别名
defaultKey: apollo
security:
oauth2:
# sso:
# login-path: http://localhost:8089/api/auth/login
client:
pre-established-redirect-uri: http://localhost:8089/api/auth/login
registered-redirect-uri: http://localhost:8089/api/auth/login
use-current-uri: false
client-id: javaboy
client-secret: 123
access-token-uri: http://localhost:1111/oauth/token #获取token地址
user-authorization-uri: http://localhost:1111/oauth/authorize #认证地址
resource:
user-info-uri: http://localhost:1111/user #获取当前用户信息地址
#security:
# oauth2:
# client:
# pre-established-redirect-uri: http://localhost:8082/login
# registered-redirect-uri: http://localhost:8082/login
# use-current-uri: false
# client-id: cfe5edd2-c5cb-422b-86e3-adf50d42d9e6
# client-secret:
# access-token-uri: https://adfsforms.mindray.com/adfs/oauth2/token #获取token地址
# user-authorization-uri: https://adfsforms.mindray.com/adfs/oauth2/authorize #认证地址
# resource:
# user-info-uri: https://adfsforms.mindray.com/adfs/oauth2/token #获取当前用户信息地址
<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor entityID="http://adfsforms.mindray.com/adfs/services/trust"
xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<!--<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
MIIC7DCCAdSgAwIBAgIQPl0hwi9BYq9ESyTRy0sK0jANBgkqhkiG9w0BAQsFADAyMTAwLgYDVQQDEydBREZTIEVuY3J5cHRpb24gLSBhZGZzZm9ybXMubWluZHJheS5jb20wHhcNMjExMTIwMDAxMDQ3WhcNMjYxMTI0MDAxMDQ3WjAyMTAwLgYDVQQDEydBREZTIEVuY3J5cHRpb24gLSBhZGZzZm9ybXMubWluZHJheS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>-->
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
MIIC5jCCAc6gAwIBAgIQY0knaAyHd6dFrQMZlL1gYjANBgkqhkiG9w0BAQsFADAvMS0wKwYDVQQDEyRBREZTIFNpZ25pbmcgLSBhZGZzZm9ybXMubWluZHJheS5jb20wHhcNMjExMTIwMDAxMDQ3WhcNMjYxMTI0MDAxMDQ3WjAvMS0wKwYDVQQDEyRBREZTIFNpZ25pbmcgLSBhZGZzZm9ybXMubWluZHJheS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvASvpK
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://adfsforms.mindray.com/adfs/ls/"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://adfsforms.mindray.com/adfs/ls/"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://adfsforms.mindray.com/adfs/ls/"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://adfsforms.mindray.com/adfs/ls/"/>
</md:IDPSSODescriptor>
</md:EntityDescriptor>
\ 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:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev-95090549.okta.com/app/dev-95090549_mairuisamldemo_1/exk67l5t6p2UNYn6l5d7/slo/saml"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://dev-95090549.okta.com/app/dev-95090549_mairuisamldemo_1/exk67l5t6p2UNYn6l5d7/slo/saml"/><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/app/dev-95090549_mairuisamldemo_1/exk67l5t6p2UNYn6l5d7/sso/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://dev-95090549.okta.com/app/dev-95090549_mairuisamldemo_1/exk67l5t6p2UNYn6l5d7/sso/saml"/></md:IDPSSODescriptor></md:EntityDescriptor>
\ No newline at end of file
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:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://dev-95090549.okta.com/app/dev-95090549_mairuisamldemo_1/exk67l5t6p2UNYn6l5d7/slo/saml"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://dev-95090549.okta.com/app/dev-95090549_mairuisamldemo_1/exk67l5t6p2UNYn6l5d7/slo/saml"/><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/app/dev-95090549_mairuisamldemo_1/exk67l5t6p2UNYn6l5d7/sso/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://dev-95090549.okta.com/app/dev-95090549_mairuisamldemo_1/exk67l5t6p2UNYn6l5d7/sso/saml"/></md:IDPSSODescriptor></md:EntityDescriptor>
\ No newline at end of file
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