Commit aa6f1410 authored by dietricf's avatar dietricf
Browse files

SI-141 Introduce Spring Security

parent dcd2c73d
/*
*******************************************************************************
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************
*/
package org.eclipse.openk.gridfailureinformation.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
@FeignClient(name = "${services.authNAuth.name}")
public interface AuthNAuthApi {
@GetMapping(value= "/portal/rest/beservice/checkAuth")
feign.Response isTokenValid(@RequestHeader("Authorization") String token);
@GetMapping( value="/portal/rest/beservice/logout")
feign.Response logout(@RequestHeader("Authorization") String token);
}
package org.eclipse.openk.gridfailureinformation.config;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Log4j2
@Configuration
public class CorsConfig {
@Value("${cors.corsEnabled}")
private boolean corsEnabled;
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
if (corsEnabled) {
log.info("Cors enabled");
registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
.allowedHeaders("*");
} else {
log.info("Cors disabled");
}
}
};
}
}
......@@ -14,17 +14,59 @@
*/
package org.eclipse.openk.gridfailureinformation.config;
import org.eclipse.openk.gridfailureinformation.config.auth.JwtAuthenticationEntryPoint;
import org.eclipse.openk.gridfailureinformation.config.auth.JwtAuthenticationTokenFilter;
import org.eclipse.openk.gridfailureinformation.config.auth.JwtTokenValidationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Autowired
private JwtTokenValidationFilter jwtTokenValidationFilter;
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Override
protected void configure(HttpSecurity security ) throws Exception {
security.httpBasic().disable();
security.csrf().disable();
protected void configure(HttpSecurity http ) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and()
.cors()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.logout().disable()
.formLogin().disable()
.anonymous()
.and()
.addFilterAfter(jwtTokenValidationFilter, BasicAuthenticationFilter.class)
.anonymous()
.and()
.addFilterAfter(jwtAuthenticationTokenFilter, BasicAuthenticationFilter.class);
}
}
/*
*******************************************************************************
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************
*/
package org.eclipse.openk.gridfailureinformation.config.auth;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
/*
*******************************************************************************
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************
*/
package org.eclipse.openk.gridfailureinformation.config.auth;
import org.keycloak.RSATokenVerifier;
import org.keycloak.representations.AccessToken;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Value("${jwt.useStaticJwt}")
private boolean useStaticJwt;
@Value("${jwt.tokenHeader}")
private String tokenHeader;
@Value("${jwt.staticJwt}")
private String staticJwt;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
String authenticationHeader = useStaticJwt ? staticJwt : request.getHeader(this.tokenHeader);
try {
SecurityContext context= SecurityContextHolder.getContext();
if(authenticationHeader != null) {
final String bearerTkn= authenticationHeader.replace("Bearer ", "");
createToken(context, bearerTkn);
}
chain.doFilter(request, response);
} catch(AuthenticationException ex) {
throw new ServletException("Authentication exception.");
}
}
private void createToken(SecurityContext context, String bearerTkn) throws ServletException {
try {
AccessToken token = RSATokenVerifier.create(bearerTkn).getToken();
List<GrantedAuthority> authorities= new ArrayList<>();
token.getRealmAccess().getRoles().stream()
.forEach( x -> authorities.add(new SimpleGrantedAuthority("ROLE_"+x.toUpperCase())));
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(token.getName(), null, authorities);
auth.setDetails(bearerTkn);
context.setAuthentication(auth);
} catch (Exception e) {
throw new ServletException("Invalid token.");
}
}
}
/*
*******************************************************************************
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************
*/
package org.eclipse.openk.gridfailureinformation.config.auth;
import feign.Response;
import lombok.extern.log4j.Log4j2;
import org.eclipse.openk.gridfailureinformation.api.AuthNAuthApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
@Component
@Log4j2
public class JwtTokenValidationFilter extends OncePerRequestFilter {
@Autowired
private AuthNAuthApi authNAuthApi;
@Value("${jwt.useStaticJwt}")
private boolean useStaticJwt;
@Value("${jwt.tokenHeader}")
private String tokenHeader;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String authenticationHeader = useStaticJwt ? null : request.getHeader(this.tokenHeader);
if(authenticationHeader != null) {
final String bearerTkn= authenticationHeader.replace("Bearer ", "");
Response res = authNAuthApi.isTokenValid(bearerTkn);
if( res.status() != HttpStatus.OK.value() ) {
final HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper((HttpServletResponse)response);
wrapper.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token expired or not valid");
chain.doFilter(request, wrapper.getResponse());
return;
}
}
chain.doFilter(request, response);
}
}
/**
******************************************************************************
* Copyright © 2017-2018 PTA GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*
******************************************************************************
*/
package org.eclipse.openk.gridfailureinformation.model;
import com.fasterxml.jackson.annotation.JsonProperty;
public class JwtToken {
@JsonProperty("access_token")
private String accessToken;
public String getAccessToken() { return accessToken; }
public void setAccessToken(String accessToken) { this.accessToken = accessToken; }
}
\ No newline at end of file
......@@ -16,27 +16,27 @@ package org.eclipse.openk.gridfailureinformation.controller;
import org.eclipse.openk.gridfailureinformation.GridFailureInformationApplication;
import org.eclipse.openk.gridfailureinformation.service.BranchService;
import org.eclipse.openk.gridfailureinformation.service.VersionService;
import org.eclipse.openk.gridfailureinformation.support.MockDataHelper;
import org.eclipse.openk.gridfailureinformation.viewmodel.BranchDto;
import org.eclipse.openk.gridfailureinformation.viewmodel.VersionDto;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import java.util.List;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest(classes = GridFailureInformationApplication.class)
@AutoConfigureMockMvc
@ActiveProfiles("test")
public class BranchControllerTest {
@MockBean
......
......@@ -24,6 +24,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import java.util.List;
......@@ -35,6 +36,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest(classes = GridFailureInformationApplication.class)
@AutoConfigureMockMvc
@ActiveProfiles("test")
public class FailureClassificationControllerTest {
@MockBean
......
......@@ -15,10 +15,8 @@
package org.eclipse.openk.gridfailureinformation.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import jdk.nashorn.internal.ir.annotations.Ignore;
import org.eclipse.openk.gridfailureinformation.GridFailureInformationApplication;
import org.eclipse.openk.gridfailureinformation.exceptions.NotFoundException;
import org.eclipse.openk.gridfailureinformation.model.TblFailureInformation;
import org.eclipse.openk.gridfailureinformation.service.FailureInformationService;
import org.eclipse.openk.gridfailureinformation.support.MockDataHelper;
import org.eclipse.openk.gridfailureinformation.viewmodel.FailureInformationDto;
......@@ -30,24 +28,20 @@ import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Date;
import java.util.UUID;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest(classes = GridFailureInformationApplication.class)
@AutoConfigureMockMvc
@ActiveProfiles("test")
public class FailureInformationControllerTest {
@MockBean
......
......@@ -24,6 +24,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import java.util.List;
......@@ -35,6 +36,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest(classes = GridFailureInformationApplication.class)
@AutoConfigureMockMvc
@ActiveProfiles("test")
public class FailureTypeControllerTest {
@MockBean
......
......@@ -24,6 +24,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import java.util.List;
......@@ -35,6 +36,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest(classes = GridFailureInformationApplication.class)
@AutoConfigureMockMvc
@ActiveProfiles("test")
public class StatusControllerTest {
@MockBean
......
......@@ -27,6 +27,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.is;
......@@ -36,6 +37,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest(classes = GridFailureInformationApplication.class)
@AutoConfigureMockMvc
@ActiveProfiles("test")
public class VersionControllerTest {
@MockBean
......
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