I created a custom filter that fetches a token and then populates the authentication object with the token-related roles
#Component
public class TokenAuthenticationFilter extends GenericFilterBean {
#Autowired
private IAMUserDAO iamUserDAO;
#Autowired
CDBUserProfileDao cdbUserProfileDao;
#Autowired
IAMOAuth2Dao iamOAuth2DAO;
final static Logger logger = Logger.getLogger(TokenAuthenticationFilter.class.getCanonicalName());
#Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest) request;
final String accessToken = httpRequest.getHeader("Authorization");
logger.info("Request with token " + accessToken + " intercepted for rba purpose");
if (!StringUtil.isBlank(accessToken)) {
ResponseEntity<String> tokenResponse = Utils.validateAccessToken(httpRequest, iamOAuth2DAO);
if (tokenResponse.getStatusCode().equals(HttpStatus.OK)) {
try {
UserProfiles userProfileResponse = cdbUserProfileDao.getCDBUserProfile(tokenResponse.getBody());
if (userProfileResponse != null) {
String action = iamUserDAO.getFbiFederatedAction(userProfileResponse.getEntid(),
userProfileResponse.getRoles().getRole());
if (!StringUtil.isBlank(action)) {
List<GrantedAuthority> authorities = Arrays.asList(action.split(",")).stream()
.map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList());
final User user = new User("", "", true, true, true, true, authorities);
final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
} catch (Exception e) {
logger.error("rba processing encounter an error " + e.getMessage());
}
}
}
logger.info("Exiting rba filter with token " + accessToken);
chain.doFilter(request, response);
}
}
I then added that filter to a springsecuritycontext as followed:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new TokenAuthenticationFilter());
registrationBean.setEnabled(false);
return registrationBean;
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
// Implementing Token based authentication in this filter
http.addFilterBefore(new TokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
http.authorizeRequests().antMatchers("/calendar/search", "/calendar/v2/search")
.access("hasRole('use-calendar') or hasRole('admin')").anyRequest().authenticated();
}
}
The application existed already and I just try to add the spring security layer. The spring security version is 4.2.3. After days trying to implement this, the TokenAuthenticationFilter is not loaded and consequently no request is filtered. Please help.
Since the application already existed before adding the Spring Security layer, I had to add the filter in the web.xml file in the below manner:
<filter>
<filter-name>tokenAuthenticationFilter</filter-name>
<filter-class>com.mycompany.authenticateb.config.TokenAuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>tokenAuthenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Related
The objective is to establish an authentication mechanism as outlined below:
Retrieve the session token from the header within OncePerRequestFilter and create an Authentication object.
Develop a custom implementation of UserDetailsService.
In the loadByUsername method, initiate a REST call to retrieve the user object utilizing the session token.
Construct a UserDetails object that can be accessed subsequently inside the RestController class through the Principal object.
Custom Implementation of OncePerRequestFilter
#Component
#Slf4j
public class SessionTokenFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
log.info("Inside session filter");
String sessionToken = request.getHeader("session-token");
log.info("Session token " + sessionToken);
if (sessionToken != null) {
Authentication authentication = new UsernamePasswordAuthenticationToken(sessionToken, null);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
}
Custom implementation of UserDetailsService
#Service
#Slf4j
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private RestTemplate restTemplate;
#Override
public UserDetails loadUserByUsername(String sessionToken) throws UsernameNotFoundException {
log.info("Inside UDS with session token " + sessionToken);
User user = null; //Make a rest call
if (sessionToken == null) {
throw new UsernameNotFoundException("Invalid session token");
}
user = new User();
user.setUsername("Harsh");
user.setPassword("Password");
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
new ArrayList<>());
}
}
Implementation of SecurityFilterChain as per Spring Boot 3.0
#Configuration
#EnableWebSecurity
public class SecurityConfiguration {
#Autowired
private UserDetailsService userDetailsService;
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((authz) -> authz.anyRequest().authenticated())
.addFilterBefore(new SessionTokenFilter(), UsernamePasswordAuthenticationFilter.class).userDetailsService(userDetailsService);
return http.build();
}
#Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
Inside my RestController class
#GetMapping("/api/content/{id}")
public List<Feed> getDetails(#PathVariable(name = "id") long id, Principal principal) {
log.info("Principal " + principal);
//Business Logic
}
I am encountering an issue where, during each request, the SessionTokenFilter is being invoked but the custom UserDetailsService is not being invoked. Consequently, I am receiving a 403 error for each request. What could be the missing element that is causing this issue?
I have created this system secured using the Spring Security. The problem is that all the configurations I have set up, are not being run and the requests are not being intercepted to be checked if they have a valid token or not. I am not using Spring Boot, however I have used some of the Spring libraries.
WebSecurityConfig.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private UserDetailsService jwtUserDetailsService;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// configure AuthenticationManager so that it knows from where to load
// user for matching credentials
// Use BCryptPasswordEncoder
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.httpBasic().disable().csrf().disable()
// dont authenticate this particular request
.authorizeRequests().antMatchers("/studentsystem2/login").permitAll().
// all other requests need to be authenticated
anyRequest().authenticated().and().
// make sure we use stateless session; session won't be used to
// store user's state.
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
JwtRequestFilter.java
#Component
public class JwtRequestFilter extends OncePerRequestFilter {
#Autowired
private LoginService loginService;
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
// JWT Token is in the form "Bearer token". Remove Bearer word and get
// only the Token
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
System.out.println("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
System.out.println("JWT Token has expired");
}
} else {
System.out.println("JWT Token does not begin with Bearer String");
}
// Once we get the token validate it.
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = loginService.loadUserByUsername(username);
// if token is valid configure Spring Security to manually set authentication
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// After setting the Authentication in the context, we specify
// that the current user is authenticated. So it passes the
// Spring Security Configurations successfully.
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
Basically, whenever I send a request to any endpoint , it will be executed perfectly well without checking if it has authorization or not. It needs to intercept the requests and allow only the ones that provide the right tokens.
All the configurations are okay in the java class files. Although, for a non-Spring Boot application, you need to add the following configuration in the web.xml file of the application. That connects the stuff together.
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I am using WebSecurityConfigurerAdapter like this
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private UserDetailServiceImpl userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;
private ApplicationUserRepository applicationUserRepository;
public WebSecurity(UserDetailServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder, ApplicationUserRepository applicationUserRepository) {
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
this.applicationUserRepository = applicationUserRepository;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint());
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(""/configuration/ui",
"/configuration/security"
"/webjars/**", "/users/social-sign-up", "client/**","/actuator/**",
"/instances","/assets/**","/home","/tables","/resources/**","/static/**",
"/css/**","/js/**","/scss/**","/templates").permitAll()
.antMatchers(HttpMethod.POST, SecurityConstants.SIGN_UP_VERIFY_URL).permitAll()
.antMatchers(HttpMethod.POST, SecurityConstants.SIGN_UP_URL).permitAll().anyRequest().authenticated()
.and().addFilter(new JWTAuthenticationFilter(authenticationManager(), applicationUserRepository))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
Then I have a BasicAuthenticationFilter like this
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
public JWTAuthorizationFilter(AuthenticationManager authManager) {
super(authManager);
}
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws IOException, ServletException {
String header = req.getHeader(SecurityConstants.HEADER_STRING);
if (header == null || !header.startsWith(SecurityConstants.TOKEN_PREFIX)) {
chain.doFilter(req, res);
return;
}
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
String token = request.getHeader(SecurityConstants.HEADER_STRING);
if (token != null) {
// parse the token.
String user = JWT.require(Algorithm.HMAC512(SecurityConstants.SECRET.getBytes())).build()
.verify(token.replace(SecurityConstants.TOKEN_PREFIX, "")).getSubject();
if (user != null) {
return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
}
return null;
}
return null;
}
}
And then I have UsernamePasswordAuthenticationFilter like this
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
private ApplicationUserRepository applicationUserRepository;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager,ApplicationUserRepository applicationUserRepository) {
this.authenticationManager = authenticationManager;
this.applicationUserRepository = applicationUserRepository;
}
#Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException {
try {
ApplicationUser creds = new ObjectMapper().readValue(req.getInputStream(), ApplicationUser.class);
System.err.println("Creds " + creds.getUsername() + ", " + creds.getPassword());
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(creds.getUsername(),
creds.getPassword(), new ArrayList<>()));
} catch (Exception e) {
// e.printStackTrace();
throw new RuntimeException(e);
}
}
#Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
Authentication auth) throws IOException, ServletException {
String token = JWT.create().withSubject(((User) auth.getPrincipal()).getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME)).sign(HMAC512(SECRET.getBytes()));
res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
res.setStatus(HttpServletResponse.SC_OK);
String userName = ((User)auth.getPrincipal()).getUsername();
ApplicationUser au= applicationUserRepository.findByUsername(userName);
String json = new ObjectMapper().writeValueAsString(au);
res.getWriter().write(json);
res.getWriter().flush();
res.getWriter().close();
}
}
I am able to generate JWT token in HEADER. Like this
Authorization →Bearer awgaagarbrqe342tewrbwrewh.23tebvre34h4wbseb43qberqbqv.23gwrwvw4hw5445jmet76e-gqgqggq323t9003qgnibqp2389bvqp9q83bv9
What I am trying to achieve is whenever the token gets expired, the client sending the latest expired token will get a new token based on the token they have sent.
So my question is, how do I generate a refresh token or a mechanism that will take the old expired token and generate a new token?
Doing this would weaken the security of the application since new tokens can be retrieved from expired ones(invalid tokens). So you should try not to do it.
If you have to do it, keep a table in the db with the tokens and their validity, then when you get an invalid jwt token exception go to db check for the said token and see when it was expired. If it was 5 mins ago then you could probably renew it otherwise don't.
I am made a sample spring boot app implementing JWT token authentication which is working partially. That means it does not let the request access the endpoints until generating the token by sending user details using /login url. Once the token is received, the token is sent with a header called Authorization. So untill the first url all with this header, it does not allow to access endpoints. But after the 1st call I can access the enpoints without the Authorization header which contains the JWT token.
SecurityConfig.java
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomUserDetailsService customUserDetailsService;
#Autowired
public SecurityConfig(CustomUserDetailsService customUserDetailsService) {
this.customUserDetailsService = customUserDetailsService;
System.out.println("from SecurityConfig constructor");
System.out.println(this.customUserDetailsService.loadUserByUsername("batman").getUsername());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("from configure");
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/sign_up").permitAll()
.antMatchers("/*/floor1/**").hasRole("USER")
.antMatchers("/*/floor2/**").hasRole("ADMIN")
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager(), customUserDetailsService));
}
}
JwtAuthenticationFilter.java
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
// {"username":"batman","password":"123"}
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
System.out.println(">>>>> AuthenticationFilter: checking user credentials....");
ApplicationUser applicationUser = new ObjectMapper().readValue(request.getInputStream(), ApplicationUser.class);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(applicationUser.getUsername(), applicationUser.getPassword()));
} catch (IOException e) {
System.out.println(">>>>> AuthenticationFilter: error in checking user credentials....");
throw new RuntimeException(e);
} catch (Exception e) {
System.out.println(">>>>> AuthenticationFilter: error in checking user credentials....");
throw new RuntimeException(e);
}
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
System.out.println(">>>>> AuthenticationFilter: successfulAuthentication creating token...");
ZonedDateTime expirationTimeUTC = ZonedDateTime.now(ZoneOffset.UTC).plus(SecurityConstants.EXPIRATION_TIME, ChronoUnit.MILLIS);
String token = Jwts.builder().setSubject(((User)authResult.getPrincipal()).getUsername())
.setExpiration(Date.from(expirationTimeUTC.toInstant()))
.signWith(SignatureAlgorithm.HS256, SecurityConstants.SECRET)
.compact();
response.getWriter().write(token);
response.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
System.out.println(">>>>> AuthenticationFilter: successfulAuthentication token created and added to response");
}
}
JwtAuthorizationFilter.java
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
private final CustomUserDetailsService customUserDetailsService;
public JwtAuthorizationFilter(AuthenticationManager authenticationManager, CustomUserDetailsService customUserDetailsService) {
super(authenticationManager);
this.customUserDetailsService = customUserDetailsService;
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String header = request.getHeader(SecurityConstants.HEADER_STRING);
System.out.println(">>>>> AuthorizationFilter doFilterInternal: checking the availability of toke header...");
if(header == null || !header.startsWith(SecurityConstants.TOKEN_PREFIX)){
System.out.println(">>>>> AuthorizationFilter doFilterInternal: header is null or not start with token prefix");
chain.doFilter(request, response);
return;
}
UsernamePasswordAuthenticationToken authenticationToken = getAuthenticationToken(request);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
chain.doFilter(request, response);
}
private UsernamePasswordAuthenticationToken getAuthenticationToken(HttpServletRequest request){
System.out.println(">>>>> AuthorizationFilter UsernamePasswordAuthentication: validating the token...");
String token = request.getHeader(SecurityConstants.HEADER_STRING);
if(token == null){
System.out.println(">>>>> AuthorizationFilter UsernamePasswordAuthentication: error: token is null");
return null;
}
String username = Jwts.parser().setSigningKey(SecurityConstants.SECRET).parseClaimsJws(token.replace(SecurityConstants.TOKEN_PREFIX, "")).getBody().getSubject();
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
ApplicationUser applicationUser = customUserDetailsService.loadApplicationUserByUsername(username);
return username != null ? new UsernamePasswordAuthenticationToken(applicationUser, null, userDetails.getAuthorities()) : null;
}
}
in JwtAuthorizationFilter.java it returns true where the token is check for null. So it is supposed to prevent accessing endpoints
and give an error to the client. But it does not. It allows the request to slip through the filter
and access the endpoint. Please help me if i am missing something here.
Complete sample project: https://github.com/xandar6/jwt
During my Spring Boot 1.3.1.RELEASE application startup I noticed a following line in the log:
Using default security password: d60d96ca-1285-41c9-aed7-d5688af74688
What does it mean and how to fix it ?
I suspect I have some issues in the my application config:
Application:
#SpringBootApplication
#EnableOAuth2Client
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
WebSecurityConfiguration:
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private OAuth2ClientContext oauth2ClientContext;
#Value("${ok.client.publicKey}")
private String okClientPublicKey;
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.headers().frameOptions().disable()
.and().logout()
.and().antMatcher("/**").authorizeRequests()
.antMatchers("/", "/login**", "/index.html", "/home.html").permitAll()
.anyRequest().authenticated()
.and().exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/"))
.and().logout().logoutSuccessUrl("/").permitAll()
.and().csrf().csrfTokenRepository(csrfTokenRepository())
.and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
// #formatter:on
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
#Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
#Bean
#ConfigurationProperties("ok")
ClientResources ok() {
return new ClientResources();
}
private Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
filters.add(ssoFilter(ok(), "/login/ok"));
filter.setFilters(filters);
return filter;
}
private Filter ssoFilter(ClientResources client, String path) {
OAuth2ClientAuthenticationProcessingFilter clientFilter = new OAuth2ClientAuthenticationProcessingFilter(path);
OAuth2RestTemplate clientTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
clientFilter.setRestTemplate(clientTemplate);
OkUsersClient okUsersClient = new OkUsersClient(client.getResource().getUserInfoUri(), okClientPublicKey,
client.getClient().getClientSecret(), clientTemplate);
clientFilter.setTokenServices(new OkUserInfoTokenServices(okUsersClient, client.getClient().getClientId()));
clientFilter.setAuthenticationSuccessHandler(new UrlParameterAuthenticationHandler());
return clientFilter;
}
class UrlParameterAuthenticationHandler extends SimpleUrlAuthenticationSuccessHandler {
#Override
protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
String targetUrl = determineTargetUrl(request, response);
if (response.isCommitted()) {
logger.debug("Response has already been committed. Unable to redirect to " + targetUrl);
return;
}
String queryString = HttpUtils.removeParams(request.getQueryString(), "state", "code");
targetUrl = !StringUtils.isEmpty(queryString) ? targetUrl + "?" + queryString : targetUrl;
getRedirectStrategy().sendRedirect(request, response, targetUrl);
}
}
class ClientResources {
private OAuth2ProtectedResourceDetails client = new AuthorizationCodeResourceDetails();
private ResourceServerProperties resource = new ResourceServerProperties();
public OAuth2ProtectedResourceDetails getClient() {
return client;
}
public ResourceServerProperties getResource() {
return resource;
}
}
}
application.yml:
server:
port: 8443
ssl:
key-store: keystore.p12
key-store-password: ***
keyStoreType: PKCS12
keyAlias: tomcat
spring:
aop:
proxy-target-class: true
ok:
client:
accessTokenUri: https://api.ok.ru/oauth/token.do
userAuthorizationUri: https://connect.ok.ru/oauth/authorize
clientId: ***
clientSecret: ***
publicKey: ***
authenticationScheme: query
clientAuthenticationScheme: form
resource:
userInfoUri: https://api.ok.ru/fb.do
logging:
file: application.log
level:
org.springframework: INFO
If you have Spring Security (you have, because of EnableOAuth2Client) in your project and don't specify a user and a password Spring Boot creates at least a secure password for you (you might want to read more in the manual)
)
If Spring Security is on the classpath then web applications will be
secure by default with ‘basic’ authentication on all HTTP endpoints.
To add method-level security to a web application you can also add
#EnableGlobalMethodSecurity with your desired settings. Additional
information can be found in the Spring Security Reference.
The default AuthenticationManager has a single user (‘user’ username
and random password, printed at INFO level when the application starts
up)
Using default security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35
You should set these values in application.properties to avoid it:
security.user.name=...
security.user.password=...
security.user.role=...
Converted to your application.yml it will look like:
security:
user:
name: ...
password: ...
role: ...