Commit 3783fe52 by lanmw

update,注销功能

parent 8c8303b2
......@@ -79,8 +79,14 @@
</dependency>
<!--引入oauth2-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.10.2</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.11.0</version>
</dependency>
<!--引入oauth2-->
<dependency>
......@@ -190,44 +196,6 @@
<version>1.11</version>
</dependency>
<!--引入saml-->
<dependency>
<groupId>org.springframework.security.extensions</groupId>
<artifactId>spring-security-saml2-core</artifactId>
<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>
......
......@@ -3,11 +3,13 @@ package com.keymobile.login;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan(basePackages = {"com.keymobile.login", "com.keymobile.config.logging", "com.keymobile.login.saml"})
@EnableFeignClients
@ComponentScan(basePackages = {"com.keymobile.login", "com.keymobile.config.logging", "com.keymobile.login.service"})
public class LoginApplication {
public static void main(String[] args) {
......
......@@ -7,6 +7,21 @@ public class Constants {
public static final String Session_UserDName = "userDName";
public static final String Session_Roles = "roles";
public static final String Session_Lang = "lang";
public static final String JWT_ACCESS_TOKEN = "access_token";
public static final String JWT_TOKEN_TYPE = "Bearer";
public static final String JWT_ID_TOKEN = "id_token";
public static final String JWT_EXPIRES_IN = "expires_in";
public static final String OAUTH_AUTHORIZE_CODE_PARAM = "code";
public static final String OAUTH_AUTHORIZE_STATE_PARAM = "state";
public static final String OAUTH_AUTHORIZE_GRANT_TYPE_PARAM = "grant_type";
public static final String OAUTH_AUTHORIZE_CLIENT_ID_PARAM = "client_id";
public static final String OAUTH_AUTHORIZE_RESPONSE_MODE = "query";
public static final String OAUTH_AUTHORIZE_STATE = "keymobile";
public static final String OAUTH_AUTHORIZE_RESPONSE_TYPE = "code";
public static final String OAUTH_AUTHORIZE_GRANT_TYPE = "authorization_code";
}
package com.keymobile.login.conf;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.auth.BasicAuthRequestInterceptor;
import feign.codec.Decoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
@Configuration
public class FeignClientConfig {
@Value("${feign.authUser}")
private String authUser;
@Value("${feign.authPwd}")
private String authPwd;
@Bean
public BasicAuthRequestInterceptor getBasicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor(authUser, authPwd);
}
@Bean
public Decoder feignDecoder() {
HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());
ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);
return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
}
public ObjectMapper customObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
return objectMapper;
}
}
\ No newline at end of file
package com.keymobile.login.conf;
import com.keymobile.login.api.Constants;
import com.keymobile.login.oauth2.Oauth2Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Component
public class LogoutProcessHandler implements LogoutHandler {
private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);
@Autowired
private Oauth2Properties oauth2Properties;
private RestTemplate restTemplate;
@PostConstruct
public void init() {
restTemplate = new RestTemplateBuilder().basicAuthorization(oauth2Properties.getClientId(), oauth2Properties.getClientSecret()).build();
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Arrays.asList(
MediaType.TEXT_HTML,
MediaType.TEXT_PLAIN));
restTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter);
}
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
Map<String, Object> params = new HashMap<>();
HttpSession session = request.getSession();
if (session != null) {
String id_token = (String)session.getAttribute(Constants.JWT_ID_TOKEN);
if (null != id_token)
params.put("id_token_hint", id_token);
}
String adfsLoginOutUri = oauth2Properties.getAuthorizationLoginOutUri();
params.put("client_id", oauth2Properties.getClientId());
log.info("loginOutADFS url is {} ", adfsLoginOutUri);
log.info("loginOutADFS params is {} ", params);
try {
restTemplate.getForEntity(adfsLoginOutUri, String.class, params);
} catch (Exception e) {
log.error("loginOut error.", e);
}
}
}
package com.keymobile.login.conf;
import com.keymobile.login.oauth2.Oauth2Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
......@@ -13,12 +15,16 @@ import java.io.IOException;
@Component
public class RESTLogoutSuccessHandler implements LogoutSuccessHandler {
@Autowired
private Oauth2Properties oauth2Properties;
@Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
response.setStatus(HttpStatus.OK.value());
response.getWriter().flush();
response.sendRedirect(oauth2Properties.getAuthorizeFullUri());
// response.setStatus(HttpStatus.OK.value());
// response.getWriter().flush();
}
}
package com.keymobile.login.conf;
import com.keymobile.auth.common.security.CustomizedUserDetailService;
import com.keymobile.login.api.Constants;
import com.keymobile.login.oauth2.Oauth2Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.web.client.RestTemplate;
//
//@Configuration
//@ComponentScan("com.keymobile.auth.common.security")
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
@Configuration
@ComponentScan("com.keymobile.auth.common.security")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// @Autowired
private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);
@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
private LogoutProcessHandler logoutProcessHandler;
private RestTemplate restTemplate = new RestTemplate();
// @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.authorizeRequests().anyRequest().authenticated();
http
.authorizeRequests()
.antMatchers("/login", "/error", "/signin", "/signout", "/oauth/**").permitAll()
.anyRequest().authenticated();
http.csrf().disable();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
http.formLogin().successHandler(authenticationSuccessHandler);
......@@ -44,4 +68,5 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
http.logout().logoutSuccessHandler(logoutSuccessHandler);
}
}
package com.keymobile.login.oauth2;
import com.keymobile.auth.common.security.CustomizedUserDetailService;
import org.springframework.boot.web.client.RestTemplateBuilder;
import com.keymobile.login.api.Constants;
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 {
......@@ -32,52 +25,72 @@ public class AccessTokenInterceptor implements HandlerInterceptor {
private CustomizedUserDetailService userDetailService;
public AccessTokenInterceptor(RestTemplate restTemplate, CustomizedUserDetailService customizedUserDetailService) {
private Oauth2Properties oauth2Properties;
public AccessTokenInterceptor(Oauth2Properties oauth2Properties, RestTemplate restTemplate, CustomizedUserDetailService customizedUserDetailService) {
this.userDetailService = customizedUserDetailService;
this.restTemplate = restTemplate;
this.oauth2Properties = oauth2Properties;
}
// 在请求处理之前,只有返回true才会执行请求
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 得到session
System.out.println( Thread.currentThread().toString() + "AccessToken request url-------------------" + request.getRequestURI());
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");
response.sendRedirect(oauth2Properties.getAuthorizationSuccessRedirectUri());
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");
String authorizeFullUri = getAuthorizeFullUri();
response.sendRedirect(authorizeFullUri);
return false;
}
return true;
}
private String getAuthorizeFullUri() {
String authorizeUri = oauth2Properties.getUserAuthorizationUri();
String clientId = oauth2Properties.getClientId();
String redirectUri = oauth2Properties.getPostLoginRedirectUri();
String response_type = Constants.OAUTH_AUTHORIZE_RESPONSE_TYPE;
String response_mode = Constants.OAUTH_AUTHORIZE_RESPONSE_MODE;
String state = Constants.OAUTH_AUTHORIZE_STATE;
String authorizeFullUri = String.format("%s?client_id=%s&redirect_uri=%s&response_type=%s&state=%s&response_model=%s",
authorizeUri, clientId, redirectUri, response_type, state, response_mode);
return authorizeFullUri;
}
private UserDetails getUserDetailByTokenInfo(HttpServletRequest request) {
String code = request.getParameter("code");
String state = request.getParameter("state");
try {
String code = request.getParameter(Constants.OAUTH_AUTHORIZE_CODE_PARAM);
String state = request.getParameter(Constants.OAUTH_AUTHORIZE_STATE_PARAM);
System.out.println("accessToken request 获取到code" + code + ",获取到state " + 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)) {
map.add("client_id", oauth2Properties.getClientId());
map.add("client_secret", oauth2Properties.getClientSecret());
map.add("redirect_uri", oauth2Properties.getPostLoginRedirectUri());
map.add("grant_type", Constants.OAUTH_AUTHORIZE_GRANT_TYPE);
Map<String, String> resp = restTemplate.postForObject(oauth2Properties.getAccessTokenUri(), map, Map.class);
Object access_token = resp.get("access_token");
Object id_token = resp.get("id_token");
Object expires_in = resp.get("expires_in");
Object token_type = resp.get("token_tpye");
}
System.out.println("获取到token......" + access_token);
System.out.println("获取到id_token......" + id_token);
String username = exactUserInfoFromToken(access_token);
String username = exactUserInfoFromToken((String)access_token);
userDetails = userDetailService.loadUserByUsername(username);
......@@ -87,18 +100,19 @@ public class AccessTokenInterceptor implements HandlerInterceptor {
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(Constants.JWT_ACCESS_TOKEN, access_token);
session.setAttribute(Constants.JWT_ID_TOKEN, id_token);
session.setAttribute(Constants.JWT_EXPIRES_IN, expires_in);
session.setAttribute(Constants.JWT_TOKEN_TYPE, token_type);
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;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 视图渲染后执行
......@@ -113,6 +127,7 @@ public class AccessTokenInterceptor implements HandlerInterceptor {
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");
}
}
}
......@@ -2,29 +2,26 @@ package com.keymobile.login.oauth2;
import com.keymobile.auth.common.security.CustomizedUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
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
//@Configuration
public class LoginConfig implements WebMvcConfigurer {
/**
* 该方法用于注册拦截器
* 可注册多个拦截器,多个拦截器组成一个拦截器链
*/
@Autowired
private CustomizedUserDetailService customizedUserDetailService;
@Autowired
private Oauth2Properties oauth2Properties;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// addPathPatterns 添加路径
// excludePathPatterns 排除路径
registry.addInterceptor(new LoginInterceptor());
registry.addInterceptor(new AccessTokenInterceptor(new RestTemplate(), customizedUserDetailService));
// .addPathPatterns("/sys/*"); // 拦截sys路径下的url
// .excludePathPatterns("");
// registry.addInterceptor(new LoginInterceptor(oauth2Properties)).excludePathPatterns("/oauth/**");
// registry.addInterceptor(new AccessTokenInterceptor(oauth2Properties,
// new RestTemplateBuilder().basicAuthorization(oauth2Properties.getClientId(),
// oauth2Properties.getClientSecret()).build(), customizedUserDetailService)).excludePathPatterns("/oauth/**");
}
}
\ No newline at end of file
package com.keymobile.login.oauth2;
import org.slf4j.LoggerFactory;
import com.keymobile.login.api.Constants;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;
......@@ -9,24 +9,34 @@ 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 {
private Oauth2Properties oauth2Properties;
public LoginInterceptor(Oauth2Properties oauth2Properties) {
this.oauth2Properties = oauth2Properties;
}
// 在请求处理之前,只有返回true才会执行请求
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 得到session
String code = request.getParameter("code");
String state = request.getParameter("state");
System.out.println(Thread.currentThread().toString() + "login request url-------------------" + request.getRequestURI());
String code = request.getParameter(Constants.OAUTH_AUTHORIZE_CODE_PARAM);
String state = request.getParameter(Constants.OAUTH_AUTHORIZE_STATE_PARAM);
System.out.println("login request 获取到code" + code + ",获取到state " + state);
if (!StringUtils.isEmpty(code) && !StringUtils.isEmpty(state)) {
return true;
}
UserDetails userDetails = null;
try {
userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (null != userDetails) {
return true;
}
} 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");
String authorizeFullUri = getAuthorizeFullUri();
response.sendRedirect(authorizeFullUri);
return false;
}
return true;
......@@ -39,4 +49,16 @@ public class LoginInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
private String getAuthorizeFullUri() {
String authorizeUri = oauth2Properties.getUserAuthorizationUri();
String clientId = oauth2Properties.getClientId();
String redirectUri = oauth2Properties.getPostLoginRedirectUri();
String response_type = Constants.OAUTH_AUTHORIZE_RESPONSE_TYPE;
String response_mode = Constants.OAUTH_AUTHORIZE_RESPONSE_MODE;
String state = Constants.OAUTH_AUTHORIZE_STATE;
String authorizeFullUri = String.format("%s?client_id=%s&redirect_uri=%s&response_type=%s&state=%s&response_model=%s",
authorizeUri, clientId, redirectUri, response_type, state, response_mode);
return authorizeFullUri;
}
}
\ 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.oauth2;
import com.keymobile.login.api.Constants;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "security.oauth2.client")
@Component
public class Oauth2Properties {
private String clientId;
private String clientSecret;
private String clientTokenUri;
private String userAuthorizationUri;
private String postLoginRedirectUri;
private String authorizationSuccessRedirectUri;
private String postLogoutRedirectUri;
private String accessTokenUri;
private String authorizationLoginOutUri;
public void setPostLogoutRedirectUri(String postLogoutRedirectUri) {
this.postLogoutRedirectUri = postLogoutRedirectUri;
}
public String getPostLogoutRedirectUri() {
return postLogoutRedirectUri;
}
public void setAuthorizationLoginOutUri(String authorizationLoginOutUri) {
this.authorizationLoginOutUri = authorizationLoginOutUri;
}
public String getAuthorizationLoginOutUri() {
return authorizationLoginOutUri;
}
public void setAccessTokenUri(String accessTokenUri) {
this.accessTokenUri = accessTokenUri;
}
public String getAccessTokenUri() {
return accessTokenUri;
}
public void setAuthorizationSuccessRedirectUri(String authorizationSuccessRedirectUri) {
this.authorizationSuccessRedirectUri = authorizationSuccessRedirectUri;
}
public String getAuthorizationSuccessRedirectUri() {
return authorizationSuccessRedirectUri;
}
public void setPostLoginRedirectUri(String postLoginRedirectUri) {
this.postLoginRedirectUri = postLoginRedirectUri;
}
public String getPostLoginRedirectUri() {
return postLoginRedirectUri;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientSecret() {
return clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public String getClientTokenUri() {
return clientTokenUri;
}
public void setClientTokenUri(String clientTokenUri) {
this.clientTokenUri = clientTokenUri;
}
public String getUserAuthorizationUri() {
return userAuthorizationUri;
}
public void setUserAuthorizationUri(String userAuthorizationUri) {
this.userAuthorizationUri = userAuthorizationUri;
}
public String getAuthorizeFullUri() {
String authorizeUri = getUserAuthorizationUri();
String clientId = getClientId();
String redirectUri = getPostLoginRedirectUri();
String response_type = Constants.OAUTH_AUTHORIZE_RESPONSE_TYPE;
String response_mode = Constants.OAUTH_AUTHORIZE_RESPONSE_MODE;
String state = Constants.OAUTH_AUTHORIZE_STATE;
String authorizeFullUri = String.format("%s?client_id=%s&redirect_uri=%s&response_type=%s&state=%s&response_model=%s",
authorizeUri, clientId, redirectUri, response_type, state, response_mode);
return authorizeFullUri;
}
}
package com.keymobile.login.saml;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@ConfigurationProperties("demo.saml.context.provider")
@Configuration
public class ContextProperties {
public ContextProperties() {};
private String schema;
private String serverName;
private String contextPath;
private int serverPort;
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
public String getContextPath() {
return contextPath;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
public int getServerPort() {
return serverPort;
}
public void setServerPort(int serverPort) {
this.serverPort = serverPort;
}
}
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.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;
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");
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);
ClassPathResource classPathResource = new ClassPathResource(privateKeyLocation);
InputStream pathResourceInputStream = classPathResource.getInputStream();
byte[] keyBytes = StreamUtils.copyToByteArray(pathResourceInputStream);
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.beans.factory.annotation.Autowired;
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();
}
@Autowired
private SamlProperties samlProperties;
@Bean
public SAMLContextProviderImpl contextProvider() {
if (samlProperties.getUseLB()) {
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;
} else {
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.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 {
/**
* 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;
//配置本身服务相关信息
@Autowired
private ContextProperties context;
private String successTargetUrl;
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;
}
public Boolean getUseLB() {
return useLB;
}
public void setSuccessTargetUrl(String successTargetUrl) {
this.successTargetUrl = successTargetUrl;
}
public String getSuccessTargetUrl() {
return successTargetUrl;
}
public void setContext(ContextProperties context) {
this.context = context;
}
public ContextProperties getContext() {
return context;
}
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 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
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 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
package com.keymobile.login.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@FeignClient(value = "authService")
public interface AuthService {
@RequestMapping(value = "/users/findByName")
List<Map<String, Object>> getUserByName(@RequestParam(value = "match") String match);
@PostMapping(value = "/users")
Map<String, Object> addUser(@RequestBody Map<String, Object> user);
}
......@@ -26,20 +26,6 @@ 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:
......@@ -55,77 +41,17 @@ redirect-url:
#80600793 H?hVm0jn
#80600745 Wenhua@015
demo:
saml:
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: false
context:
provider:
schema: http
serverName: localhost
contextPath: /api/auth
serverPort: 8089
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:
# client-id: javaboy
# client-secret: 123
# access-token-uri: http://localhost:1111/oauth/token #获取token地址
# user-authorization-uri: http://localhost:1111/oauth/authorize #认证地址
# redirect-uri: http://localhost:8089/api/auth/login #系统首页登录地址
# authorization-success-redirect-uri: http://localhost:8089/center-home/menu/index #认证成功后跳转地址
# authorization-login-out-uri: http://localhost:1111/signout
#security:
# oauth2:
......@@ -140,6 +66,20 @@ security:
# resource:
# user-info-uri: https://adfsforms.mindray.com/adfs/oauth2/token #获取当前用户信息地址
security:
oauth2:
client:
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 #认证地址
authorization-success-redirect-uri: http://localhost:8089/center-home/menu/index #认证成功后跳转地址
authorization-login-out-uri: https://adfsforms.mindray.com/adfs/oauth2/logout
post-login-redirect-uri: http://localhost:8089/api/auth/login #adfs登录后回调系统的登录接口
post-logout-redirect_uri: http://localhost:8089/api/auth/signout #adfs退出后回调系统的注销接口
feign:
authUser: root
authPwd: pwd
......
<?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
-----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