Revize 997c4599
Přidáno uživatelem Petr Urban před více než 1 rok
pom.xml | ||
---|---|---|
5 | 5 |
<parent> |
6 | 6 |
<groupId>org.springframework.boot</groupId> |
7 | 7 |
<artifactId>spring-boot-starter-parent</artifactId> |
8 |
<version>2.4.4</version>
|
|
8 |
<version>2.7.18</version>
|
|
9 | 9 |
<relativePath/> <!-- lookup parent from repository --> |
10 | 10 |
</parent> |
11 | 11 |
|
... | ... | |
77 | 77 |
</dependencyManagement> |
78 | 78 |
|
79 | 79 |
<dependencies> |
80 |
|
|
81 |
|
|
82 |
<dependency> |
|
83 |
<groupId>org.springframework.boot</groupId> |
|
84 |
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId> |
|
85 |
<version>2.7.5</version> |
|
86 |
</dependency> |
|
87 |
|
|
88 |
<dependency> |
|
89 |
<groupId>org.springframework.boot</groupId> |
|
90 |
<artifactId>spring-boot-starter-web</artifactId> |
|
91 |
<version>2.7.5</version> |
|
92 |
</dependency> |
|
93 |
|
|
94 |
<dependency> |
|
95 |
<groupId>org.apache.commons</groupId> |
|
96 |
<artifactId>commons-lang3</artifactId> |
|
97 |
<version>3.13.0</version> |
|
98 |
</dependency> |
|
99 |
|
|
80 | 100 |
<dependency> |
81 | 101 |
<groupId>org.projectlombok</groupId> |
82 | 102 |
<artifactId>lombok</artifactId> |
... | ... | |
88 | 108 |
<artifactId>spring-boot-starter</artifactId> |
89 | 109 |
</dependency> |
90 | 110 |
|
111 |
|
|
91 | 112 |
<dependency> |
92 | 113 |
<groupId>org.springframework.boot</groupId> |
93 | 114 |
<artifactId>spring-boot-starter-test</artifactId> |
... | ... | |
95 | 116 |
</dependency> |
96 | 117 |
|
97 | 118 |
<dependency> |
98 |
<groupId>org.springframework.boot</groupId> |
|
99 |
<artifactId>spring-boot-starter-web</artifactId> |
|
100 |
</dependency> |
|
101 |
|
|
102 |
<dependency> |
|
103 |
<groupId>org.springframework.security</groupId> |
|
104 |
<artifactId>spring-security-web</artifactId> |
|
105 |
</dependency> |
|
106 |
|
|
107 |
<dependency> |
|
108 |
<groupId>mysql</groupId> |
|
109 |
<artifactId>mysql-connector-java</artifactId> |
|
119 |
<groupId>com.mysql</groupId> |
|
120 |
<artifactId>mysql-connector-j</artifactId> |
|
110 | 121 |
<scope>runtime</scope> |
111 | 122 |
</dependency> |
112 | 123 |
|
src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/exception/CustomErrorController.java | ||
---|---|---|
64 | 64 |
return errorPage; |
65 | 65 |
} |
66 | 66 |
|
67 |
@Override |
|
68 |
public String getErrorPath() { |
|
69 |
return "/error"; |
|
70 |
} |
|
71 | 67 |
|
72 | 68 |
} |
src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/MainController.java | ||
---|---|---|
1 |
package cz.zcu.fav.kiv.antipatterndetectionapp.v2.controller; |
|
2 |
|
|
3 |
import org.springframework.http.ResponseEntity; |
|
4 |
import org.springframework.web.bind.annotation.GetMapping; |
|
5 |
import org.springframework.web.bind.annotation.RequestMapping; |
|
6 |
import org.springframework.web.bind.annotation.RestController; |
|
7 |
|
|
8 |
@RestController |
|
9 |
@RequestMapping("/v2") |
|
10 |
public class MainController { |
|
11 |
|
|
12 |
@GetMapping(value = "/testCall", produces = "application/json") |
|
13 |
public ResponseEntity<String> TestController() { |
|
14 |
String response = "{\"response\": \"successfully called\"}"; |
|
15 |
|
|
16 |
return ResponseEntity.ok().body(response); |
|
17 |
} |
|
18 |
|
|
19 |
} |
src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/UserController.java | ||
---|---|---|
24 | 24 |
@RequestMapping("v2/user") |
25 | 25 |
public class UserController { |
26 | 26 |
|
27 |
@Autowired |
|
28 |
private AuthenticationManager authenticationManager; |
|
29 |
|
|
30 |
/** |
|
31 |
* Service for work with user management |
|
32 |
*/ |
|
33 |
@Autowired |
|
34 |
private UserService userService; |
|
35 |
|
|
36 |
/** |
|
37 |
* Service for login, logout and authenticate |
|
38 |
*/ |
|
39 |
@Autowired |
|
40 |
private OAuthService aOuthService; |
|
41 |
|
|
42 |
/** |
|
43 |
* Method to register new user in the app |
|
44 |
* |
|
45 |
* @param user User who wants register in to the app |
|
46 |
* @return message |
|
47 |
*/ |
|
48 |
@PostMapping(value = "/register") |
|
49 |
public ResponseEntity<String> registerUser(@RequestBody User user) { |
|
50 |
UserModelStatusCodes statusCode = userService.registerUser(user); |
|
51 |
return getResponseEntity(statusCode, null); |
|
52 |
} |
|
53 |
|
|
54 |
/** |
|
55 |
* Method to login user in to the app |
|
56 |
* |
|
57 |
* @param user User who wants to login in to the app |
|
58 |
* @return message |
|
59 |
*/ |
|
60 |
@PostMapping(value = "/login") |
|
61 |
public ResponseEntity<String> loginUser(@RequestBody User user) { |
|
62 |
UserModelStatusCodes statusCode = userService.verifyUser(user); |
|
63 |
// ResponseEntity<String> response = aOuthService.loginUser(user); |
|
64 |
|
|
65 |
String jwtToken = null; |
|
66 |
if (statusCode.getStatusCode() == 200) { |
|
67 |
ResponseEntity<String> response = aOuthService.loginUser(user); |
|
68 |
jwtToken = response.getBody(); |
|
69 |
} |
|
70 |
|
|
71 |
return getResponseEntity(statusCode, jwtToken); |
|
72 |
} |
|
73 |
|
|
74 |
/** |
|
75 |
* Method to logout user from the app |
|
76 |
* |
|
77 |
* @param user User who wants logout from the app |
|
78 |
* @return message after logout |
|
79 |
*/ |
|
80 |
@PostMapping(value = "/logout") |
|
81 |
public ResponseEntity<String> logoutUser(@RequestHeader HttpHeaders headers, @RequestBody User user) { |
|
82 |
final String authHeader = headers.getFirst(HttpHeaders.AUTHORIZATION); |
|
83 |
if(authHeader == null || !authHeader.startsWith("Bearer")){ |
|
84 |
//chyba |
|
85 |
} |
|
86 |
final String token = authHeader.substring(7); |
|
87 |
user.setToken(token); |
|
88 |
return aOuthService.logoutUser(user); |
|
89 |
} |
|
90 |
|
|
91 |
@GetMapping("/refresh") |
|
92 |
public ResponseEntity<String> refreshToken(@RequestHeader HttpHeaders headers) { |
|
93 |
final String authHeader = headers.getFirst(HttpHeaders.AUTHORIZATION); |
|
94 |
if (authHeader == null || !authHeader.startsWith("Bearer")) { |
|
95 |
return getResponseEntity(UserModelStatusCodes.USER_LOGIN_FAILED, UserModelStatusCodes.USER_LOGIN_FAILED.getLabel()); |
|
96 |
} |
|
97 |
final String token = authHeader.substring(7); |
|
98 |
|
|
99 |
String jwtToken = null; |
|
100 |
ResponseEntity<String> response = aOuthService.refreshToken(token); |
|
101 |
|
|
102 |
if (response.getStatusCode().is2xxSuccessful()) { |
|
103 |
jwtToken = response.getBody(); |
|
104 |
return getResponseEntity(UserModelStatusCodes.TOKEN_REFRESHED, jwtToken); |
|
105 |
} |
|
106 |
|
|
107 |
return getResponseEntity(UserModelStatusCodes.TOKEN_EXPIRED, UserModelStatusCodes.TOKEN_EXPIRED.getLabel()); |
|
108 |
|
|
109 |
} |
|
110 | 27 |
|
111 | 28 |
/** |
112 | 29 |
* Method to create response |
src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/AuthConfiguration.java | ||
---|---|---|
1 |
package cz.zcu.fav.kiv.antipatterndetectionapp.v2.security; |
|
2 |
|
|
3 |
import com.nimbusds.jose.jwk.source.JWKSource; |
|
4 |
import com.nimbusds.jose.jwk.source.RemoteJWKSet; |
|
5 |
import com.nimbusds.jwt.proc.JWTProcessor; |
|
6 |
import org.springframework.context.annotation.Bean; |
|
7 |
import org.springframework.context.annotation.Configuration; |
|
8 |
import org.springframework.core.annotation.Order; |
|
9 |
import org.springframework.security.config.Customizer; |
|
10 |
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
|
11 |
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; |
|
12 |
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; |
|
13 |
import org.springframework.security.oauth2.jwt.JwtDecoder; |
|
14 |
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; |
|
15 |
import org.springframework.security.web.SecurityFilterChain; |
|
16 |
|
|
17 |
|
|
18 |
import com.nimbusds.jose.EncryptionMethod; |
|
19 |
import com.nimbusds.jose.JWEAlgorithm; |
|
20 |
import com.nimbusds.jose.JWSAlgorithm; |
|
21 |
import com.nimbusds.jose.jwk.JWKSet; |
|
22 |
import com.nimbusds.jose.jwk.KeyUse; |
|
23 |
import com.nimbusds.jose.jwk.RSAKey; |
|
24 |
import com.nimbusds.jose.jwk.source.ImmutableJWKSet; |
|
25 |
import com.nimbusds.jose.jwk.source.JWKSource; |
|
26 |
import com.nimbusds.jose.jwk.source.RemoteJWKSet; |
|
27 |
import com.nimbusds.jose.proc.JWEDecryptionKeySelector; |
|
28 |
import com.nimbusds.jose.proc.JWEKeySelector; |
|
29 |
import com.nimbusds.jose.proc.JWSKeySelector; |
|
30 |
import com.nimbusds.jose.proc.JWSVerificationKeySelector; |
|
31 |
import com.nimbusds.jose.proc.SecurityContext; |
|
32 |
import com.nimbusds.jose.util.Base64URL; |
|
33 |
import com.nimbusds.jwt.proc.ConfigurableJWTProcessor; |
|
34 |
import com.nimbusds.jwt.proc.DefaultJWTProcessor; |
|
35 |
import com.nimbusds.jwt.proc.JWTProcessor; |
|
36 |
|
|
37 |
import org.springframework.beans.factory.annotation.Value; |
|
38 |
import org.springframework.context.annotation.Bean; |
|
39 |
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
|
40 |
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; |
|
41 |
import org.springframework.security.oauth2.jwt.JwtDecoder; |
|
42 |
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; |
|
43 |
import org.springframework.security.web.SecurityFilterChain; |
|
44 |
import org.springframework.web.cors.CorsConfiguration; |
|
45 |
import org.springframework.web.cors.CorsConfigurationSource; |
|
46 |
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
|
47 |
import org.springframework.web.servlet.config.annotation.CorsRegistry; |
|
48 |
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
|
49 |
|
|
50 |
import java.net.URL; |
|
51 |
import java.security.interfaces.RSAPrivateCrtKey; |
|
52 |
import java.util.Arrays; |
|
53 |
|
|
54 |
import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS; |
|
55 |
|
|
56 |
@EnableWebSecurity |
|
57 |
public class AuthConfiguration { |
|
58 |
@Bean |
|
59 |
public SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) throws Exception { |
|
60 |
http |
|
61 |
.cors() |
|
62 |
.and() |
|
63 |
.authorizeRequests(authz -> authz |
|
64 |
.antMatchers("/v2/app/metadata/**", "/v2/user/register").permitAll() // Allow all requests to /v2/app/metadata/** |
|
65 |
.antMatchers("/v2/**").hasAnyRole("spade_basic") |
|
66 |
.anyRequest().authenticated() |
|
67 |
) |
|
68 |
.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwtConfigurer -> jwtConfigurer.jwtAuthenticationConverter(new JwtAuthenticationTokenConverter()))) |
|
69 |
.sessionManagement(session -> session.sessionCreationPolicy(STATELESS)); |
|
70 |
return http.build(); |
|
71 |
} |
|
72 |
|
|
73 |
@Bean |
|
74 |
public WebMvcConfigurer corsConfigurer() { |
|
75 |
return new WebMvcConfigurer() { |
|
76 |
@Override |
|
77 |
public void addCorsMappings(CorsRegistry registry) { |
|
78 |
registry.addMapping("/**") |
|
79 |
.allowedMethods("GET", "POST", "OPTIONS", "PUT", "DELETE", "PATCH") |
|
80 |
.allowedHeaders("authorization", "content-type") |
|
81 |
.allowedOrigins("http://localhost:3000") |
|
82 |
.allowCredentials(true); |
|
83 |
} |
|
84 |
}; |
|
85 |
} |
|
86 |
|
|
87 |
} |
src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/JwtAuthenticationFilter.java | ||
---|---|---|
1 |
package cz.zcu.fav.kiv.antipatterndetectionapp.v2.security; |
|
2 |
|
|
3 |
import cz.zcu.fav.kiv.antipatterndetectionapp.v2.config.SecurityBasics; |
|
4 |
import cz.zcu.fav.kiv.antipatterndetectionapp.v2.service.oauth.OAuthService; |
|
5 |
import org.springframework.http.*; |
|
6 |
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
|
7 |
import org.springframework.security.core.Authentication; |
|
8 |
import org.springframework.security.core.context.SecurityContextHolder; |
|
9 |
import org.springframework.security.core.userdetails.User; |
|
10 |
import org.springframework.security.core.userdetails.UserDetails; |
|
11 |
import org.springframework.stereotype.Component; |
|
12 |
import org.springframework.web.client.HttpClientErrorException; |
|
13 |
import org.springframework.web.filter.OncePerRequestFilter; |
|
14 |
|
|
15 |
import javax.servlet.FilterChain; |
|
16 |
import javax.servlet.ServletException; |
|
17 |
import javax.servlet.http.HttpServletRequest; |
|
18 |
import javax.servlet.http.HttpServletResponse; |
|
19 |
import java.io.IOException; |
|
20 |
import java.util.Arrays; |
|
21 |
import java.util.Collections; |
|
22 |
|
|
23 |
@Component |
|
24 |
public class JwtAuthenticationFilter extends OncePerRequestFilter { |
|
25 |
|
|
26 |
private final OAuthService oAuthService; |
|
27 |
|
|
28 |
public JwtAuthenticationFilter(OAuthService oAuthService) { |
|
29 |
this.oAuthService = oAuthService; |
|
30 |
} |
|
31 |
|
|
32 |
@Override |
|
33 |
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) |
|
34 |
throws IOException, ServletException { |
|
35 |
|
|
36 |
String authorizationHeader = request.getHeader("Authorization"); |
|
37 |
if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) { |
|
38 |
// chain.doFilter(request, response); |
|
39 |
SecurityContextHolder.clearContext(); |
|
40 |
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); |
|
41 |
response.getOutputStream().println("{\"message\" : \"Authentication failed\"}"); |
|
42 |
return; |
|
43 |
} |
|
44 |
|
|
45 |
try { |
|
46 |
String token = authorizationHeader.replace("Bearer ", ""); |
|
47 |
ResponseEntity<String> responseEntity = oAuthService.authenticate(token); |
|
48 |
|
|
49 |
UserDetails userDetails = User.builder() |
|
50 |
.username(responseEntity.getBody()) |
|
51 |
.password("") |
|
52 |
.authorities(Collections.emptyList()) |
|
53 |
.build(); |
|
54 |
|
|
55 |
Authentication auth = new UsernamePasswordAuthenticationToken(userDetails, token, userDetails.getAuthorities()); |
|
56 |
SecurityContextHolder.getContext().setAuthentication(auth); |
|
57 |
/* |
|
58 |
else { |
|
59 |
SecurityContextHolder.clearContext(); |
|
60 |
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); |
|
61 |
response.getOutputStream().println("{\"error\" : \"Token timed out!\"}"); |
|
62 |
return; |
|
63 |
}*/ |
|
64 |
} |
|
65 |
//4xx or 5xx http response from auth application |
|
66 |
//basically copies the response from auth app and send it to client |
|
67 |
catch (HttpClientErrorException e){ |
|
68 |
SecurityContextHolder.clearContext(); |
|
69 |
//read response body |
|
70 |
String responseBody = e.getResponseBodyAsString(); |
|
71 |
response.setStatus(e.getStatusCode().value()); |
|
72 |
response.getOutputStream().println(responseBody); |
|
73 |
return; |
|
74 |
} |
|
75 |
|
|
76 |
chain.doFilter(request, response); |
|
77 |
} |
|
78 |
|
|
79 |
@Override |
|
80 |
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { |
|
81 |
String path = request.getRequestURI().substring(request.getContextPath().length()); |
|
82 |
return Arrays.stream(SecurityBasics.NO_AUTHORIZATION_NEEDED).anyMatch(path::startsWith); |
|
83 |
} |
|
84 |
|
|
85 |
|
|
86 |
} |
|
87 |
|
src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/JwtAuthenticationTokenConverter.java | ||
---|---|---|
1 |
package cz.zcu.fav.kiv.antipatterndetectionapp.v2.security; |
|
2 |
|
|
3 |
import org.springframework.core.convert.converter.Converter; |
|
4 |
import org.springframework.security.authentication.AbstractAuthenticationToken; |
|
5 |
import org.springframework.security.core.GrantedAuthority; |
|
6 |
import org.springframework.security.core.authority.SimpleGrantedAuthority; |
|
7 |
import org.springframework.security.oauth2.jwt.Jwt; |
|
8 |
import org.springframework.security.oauth2.jwt.JwtClaimNames; |
|
9 |
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; |
|
10 |
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; |
|
11 |
|
|
12 |
import java.util.Collection; |
|
13 |
import java.util.Collections; |
|
14 |
import java.util.Map; |
|
15 |
import java.util.stream.Collectors; |
|
16 |
import java.util.stream.Stream; |
|
17 |
|
|
18 |
public class JwtAuthenticationTokenConverter implements Converter<Jwt, AbstractAuthenticationToken> { |
|
19 |
|
|
20 |
private static final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); |
|
21 |
private String resourceId = "spade-client"; |
|
22 |
private String principalAttribute = "preferred_username"; |
|
23 |
|
|
24 |
@Override |
|
25 |
public AbstractAuthenticationToken convert(Jwt jwt) { |
|
26 |
Collection<GrantedAuthority> authorities = |
|
27 |
Stream.concat(jwtGrantedAuthoritiesConverter.convert(jwt).stream(), extractResourceRoles(jwt).stream()) |
|
28 |
.collect(Collectors.toSet()); |
|
29 |
String claimName = principalAttribute == null ? JwtClaimNames.SUB : principalAttribute; |
|
30 |
return new JwtAuthenticationToken(jwt, authorities, jwt.getClaim(claimName)); |
|
31 |
} |
|
32 |
|
|
33 |
private Collection<? extends GrantedAuthority> extractResourceRoles(Jwt jwt) { |
|
34 |
Map<String, Object> resourceAccess = jwt.getClaim("resource_access"); |
|
35 |
Map<String, Object> resource; |
|
36 |
Collection<String> resourceRoles; |
|
37 |
if (resourceAccess == null |
|
38 |
|| (resource = (Map<String, Object>) resourceAccess.get(resourceId)) == null |
|
39 |
|| (resourceRoles = (Collection<String>) resource.get("roles")) == null) { |
|
40 |
return Collections.emptySet(); |
|
41 |
} |
|
42 |
return resourceRoles.stream() |
|
43 |
.map(role -> new SimpleGrantedAuthority("ROLE_" + role)) |
|
44 |
.collect(Collectors.toSet()); |
|
45 |
} |
|
46 |
|
|
47 |
} |
src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/WebSecurityConfig.java | ||
---|---|---|
1 |
package cz.zcu.fav.kiv.antipatterndetectionapp.v2.security; |
|
2 |
|
|
3 |
import cz.zcu.fav.kiv.antipatterndetectionapp.v2.config.SecurityBasics; |
|
4 |
import cz.zcu.fav.kiv.antipatterndetectionapp.v2.service.oauth.AuthProvider; |
|
5 |
import cz.zcu.fav.kiv.antipatterndetectionapp.v2.service.oauth.OAuthService; |
|
6 |
import org.springframework.beans.factory.annotation.Autowired; |
|
7 |
import org.springframework.boot.web.servlet.FilterRegistrationBean; |
|
8 |
import org.springframework.context.annotation.Bean; |
|
9 |
import org.springframework.context.annotation.Configuration; |
|
10 |
import org.springframework.security.authentication.AuthenticationManager; |
|
11 |
import org.springframework.security.authentication.AuthenticationProvider; |
|
12 |
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; |
|
13 |
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
|
14 |
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; |
|
15 |
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; |
|
16 |
import org.springframework.security.config.http.SessionCreationPolicy; |
|
17 |
import org.springframework.security.core.userdetails.UserDetailsService; |
|
18 |
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; |
|
19 |
import org.springframework.web.client.RestTemplate; |
|
20 |
import org.springframework.web.cors.CorsConfiguration; |
|
21 |
import org.springframework.web.cors.CorsConfigurationSource; |
|
22 |
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
|
23 |
|
|
24 |
import java.util.Arrays; |
|
25 |
|
|
26 |
@Configuration |
|
27 |
@EnableWebSecurity(debug = true) |
|
28 |
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { |
|
29 |
|
|
30 |
@Autowired |
|
31 |
private UserDetailsService userService; |
|
32 |
|
|
33 |
@Autowired |
|
34 |
private JwtAuthenticationFilter jwtAuthenticationFilter; |
|
35 |
|
|
36 |
@Autowired |
|
37 |
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { |
|
38 |
auth.userDetailsService(userService); |
|
39 |
} |
|
40 |
|
|
41 |
@Bean |
|
42 |
public AuthenticationProvider provider() { |
|
43 |
return new AuthProvider(template()); |
|
44 |
} |
|
45 |
|
|
46 |
@Bean |
|
47 |
public RestTemplate template() { |
|
48 |
return new RestTemplate(); |
|
49 |
} |
|
50 |
|
|
51 |
@Bean |
|
52 |
public UserDetailsService userDetailsService() { |
|
53 |
return super.userDetailsService(); |
|
54 |
} |
|
55 |
|
|
56 |
@Bean |
|
57 |
public FilterRegistrationBean filterRegistrationBean(OAuthService oAuthService) { |
|
58 |
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); |
|
59 |
filterRegistrationBean.setFilter(jwtAuthenticationFilter); |
|
60 |
return filterRegistrationBean; |
|
61 |
} |
|
62 |
|
|
63 |
@Override |
|
64 |
@Bean |
|
65 |
public AuthenticationManager authenticationManagerBean() throws Exception { |
|
66 |
return super.authenticationManagerBean(); |
|
67 |
} |
|
68 |
|
|
69 |
|
|
70 |
@Override |
|
71 |
protected void configure(HttpSecurity httpSecurity) throws Exception { |
|
72 |
httpSecurity |
|
73 |
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) |
|
74 |
.cors().configurationSource(corsConfigurationSource()) |
|
75 |
.and() |
|
76 |
.csrf().disable() |
|
77 |
.authorizeRequests() |
|
78 |
.mvcMatchers(SecurityBasics.NO_AUTHORIZATION_NEEDED).permitAll() |
|
79 |
.anyRequest().authenticated() |
|
80 |
.and() |
|
81 |
.sessionManagement() |
|
82 |
.sessionCreationPolicy(SessionCreationPolicy.STATELESS); |
|
83 |
} |
|
84 |
|
|
85 |
@Bean |
|
86 |
public CorsConfigurationSource corsConfigurationSource() { |
|
87 |
CorsConfiguration configuration = new CorsConfiguration(); |
|
88 |
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); |
|
89 |
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")); |
|
90 |
configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token")); |
|
91 |
configuration.setExposedHeaders(Arrays.asList("x-auth-token")); |
|
92 |
configuration.setAllowCredentials(true); |
|
93 |
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); |
|
94 |
source.registerCorsConfiguration("/**", configuration); |
|
95 |
return source; |
|
96 |
} |
|
97 |
|
|
98 |
} |
src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/AuthProvider.java | ||
---|---|---|
17 | 17 |
import org.springframework.stereotype.Service; |
18 | 18 |
import org.springframework.web.client.RestTemplate; |
19 | 19 |
|
20 |
@Service |
|
21 | 20 |
public class AuthProvider implements AuthenticationProvider { |
22 | 21 |
|
23 | 22 |
@Value("${auth.realm.authenticate}") |
24 | 23 |
private String auth_url; |
25 | 24 |
|
26 |
private RestTemplate template; |
|
25 |
// private RestTemplate template;
|
|
27 | 26 |
|
28 |
public AuthProvider(RestTemplate restTemplate){ |
|
29 |
this.template = restTemplate; |
|
30 |
} |
|
27 |
// public AuthProvider(RestTemplate restTemplate){
|
|
28 |
// this.template = restTemplate;
|
|
29 |
// }
|
|
31 | 30 |
|
32 | 31 |
|
33 | 32 |
@Override |
src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/OAuthService.java | ||
---|---|---|
8 | 8 |
|
9 | 9 |
public interface OAuthService { |
10 | 10 |
public ResponseEntity<String> authenticate(String token); |
11 |
ResponseEntity<String> authenticate(HttpServletRequest request); |
|
11 | 12 |
public ResponseEntity<String> loginUser(User user); |
12 | 13 |
public ResponseEntity<String> logoutUser(User user); |
13 | 14 |
|
src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/OAuthServiceImpl.java | ||
---|---|---|
4 | 4 |
import cz.zcu.fav.kiv.antipatterndetectionapp.v2.service.user.UserService; |
5 | 5 |
import cz.zcu.fav.kiv.antipatterndetectionapp.v2.utils.RequestBuilder; |
6 | 6 |
import org.springframework.beans.factory.annotation.Autowired; |
7 |
import org.springframework.http.HttpRequest; |
|
7 | 8 |
import org.springframework.http.ResponseEntity; |
8 | 9 |
import org.springframework.security.core.userdetails.UserDetails; |
9 | 10 |
import org.springframework.security.core.userdetails.UserDetailsService; |
10 | 11 |
import org.springframework.security.core.userdetails.UsernameNotFoundException; |
11 | 12 |
import org.springframework.stereotype.Service; |
12 | 13 |
|
14 |
import javax.servlet.http.HttpServletRequest; |
|
13 | 15 |
import java.util.ArrayList; |
14 | 16 |
import java.util.HashMap; |
15 | 17 |
import java.util.Map; |
... | ... | |
56 | 58 |
return requestBuilder.sendRequestResponse(AUTH_URL_AUTH, token); |
57 | 59 |
} |
58 | 60 |
|
61 |
@Override |
|
62 |
public ResponseEntity<String> authenticate(HttpServletRequest request) { |
|
63 |
return requestBuilder.resendHttpRequest(request, AUTH_URL_AUTH); |
|
64 |
} |
|
65 |
|
|
59 | 66 |
public ResponseEntity<String> loginUser(User user) { |
60 | 67 |
final String userName = user.getName(); |
61 | 68 |
|
src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/utils/RequestBuilder.java | ||
---|---|---|
3 | 3 |
import cz.zcu.fav.kiv.antipatterndetectionapp.v2.httpErrorHandler.CustomErrorHandler; |
4 | 4 |
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; |
5 | 5 |
import org.springframework.stereotype.Component; |
6 |
import org.springframework.util.StreamUtils; |
|
6 | 7 |
import org.springframework.web.client.RestTemplate; |
8 |
|
|
9 |
import java.io.IOException; |
|
10 |
import java.io.InputStream; |
|
11 |
import java.nio.charset.StandardCharsets; |
|
12 |
import java.util.Enumeration; |
|
7 | 13 |
import java.util.Map; |
8 | 14 |
import java.util.logging.Level; |
9 | 15 |
import java.util.logging.Logger; |
10 | 16 |
import org.springframework.http.*; |
11 | 17 |
|
18 |
import javax.servlet.http.HttpServletRequest; |
|
19 |
|
|
12 | 20 |
@Component |
13 | 21 |
public class RequestBuilder { |
14 | 22 |
private static Logger logger = Logger.getLogger(RequestBuilder.class.getName()); |
15 | 23 |
|
24 |
public ResponseEntity<String> resendHttpRequest(HttpServletRequest request, String authenticationUrl) { |
|
25 |
try { |
|
26 |
// Extract request method, headers, and body from the original request |
|
27 |
String method = request.getMethod(); |
|
28 |
HttpHeaders headers = extractHeaders(request); |
|
29 |
headers.add(HttpHeaders.HOST, "http://localhost:8080"); |
|
30 |
String body = extractBody(request); |
|
31 |
|
|
32 |
// Create a new RestTemplate instance |
|
33 |
RestTemplate restTemplate = new RestTemplate(); |
|
34 |
restTemplate.setErrorHandler(new CustomErrorHandler()); |
|
35 |
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory()); |
|
36 |
|
|
37 |
// Set Authorization header with the provided token |
|
38 |
// headers.set(HttpHeaders.AUTHORIZATION, "Bearer " + token); |
|
39 |
|
|
40 |
// Create an HttpEntity with headers and body |
|
41 |
HttpEntity<String> entity = new HttpEntity<>(body, headers); |
|
42 |
|
|
43 |
// Determine the appropriate exchange method based on the original request method |
|
44 |
ResponseEntity<String> response; |
|
45 |
if ("GET".equalsIgnoreCase(method)) { |
|
46 |
response = restTemplate.exchange(authenticationUrl, HttpMethod.GET, entity, String.class); |
|
47 |
} else if ("POST".equalsIgnoreCase(method)) { |
|
48 |
response = restTemplate.exchange(authenticationUrl, HttpMethod.POST, entity, String.class); |
|
49 |
} else { |
|
50 |
// Handle other HTTP methods as needed |
|
51 |
// ... |
|
52 |
|
|
53 |
// For simplicity, in this example, we assume other methods are handled as POST requests |
|
54 |
response = restTemplate.exchange(authenticationUrl, HttpMethod.POST, entity, String.class); |
|
55 |
} |
|
56 |
|
|
57 |
logger.log(Level.FINE, "Successfully resent HTTP request to: " + authenticationUrl); |
|
58 |
return response; |
|
59 |
} catch (Exception e) { |
|
60 |
logger.log(Level.SEVERE, "Error resending HTTP request", e); |
|
61 |
// Handle the exception as needed |
|
62 |
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error resending HTTP request"); |
|
63 |
} |
|
64 |
} |
|
65 |
|
|
66 |
// Helper method to extract headers from HttpServletRequest |
|
67 |
private HttpHeaders extractHeaders(HttpServletRequest request) { |
|
68 |
HttpHeaders headers = new HttpHeaders(); |
|
69 |
Enumeration<String> headerNames = request.getHeaderNames(); |
|
70 |
while (headerNames.hasMoreElements()) { |
|
71 |
String headerName = headerNames.nextElement(); |
|
72 |
Enumeration<String> headerValues = request.getHeaders(headerName); |
|
73 |
while (headerValues.hasMoreElements()) { |
|
74 |
String headerValue = headerValues.nextElement(); |
|
75 |
headers.add(headerName, headerValue); |
|
76 |
} |
|
77 |
} |
|
78 |
return headers; |
|
79 |
} |
|
80 |
|
|
81 |
// Helper method to extract body from HttpServletRequest |
|
82 |
private String extractBody(HttpServletRequest request) throws IOException { |
|
83 |
try (InputStream inputStream = request.getInputStream()) { |
|
84 |
return StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8); |
|
85 |
} |
|
86 |
} |
|
87 |
|
|
16 | 88 |
public ResponseEntity<String> sendRequestResponse(String url, Map<String, Object> body) { |
17 | 89 |
RestTemplate restTemplate = new RestTemplate(); |
18 | 90 |
restTemplate.setErrorHandler(new CustomErrorHandler()); |
src/main/resources/application.properties | ||
---|---|---|
12 | 12 |
# mssql database connection: |
13 | 13 |
spring.second-datasource.jdbc-url=jdbc:sqlserver://localhost:1433;databaseName=authspade;encrypt=true;trustServerCertificate=true |
14 | 14 |
spring.second-datasource.username=test |
15 |
spring.second-datasource.password= |
|
15 |
spring.second-datasource.password=test
|
|
16 | 16 |
spring.second-datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver |
17 | 17 |
|
18 | 18 |
# admin account username and password: |
... | ... | |
34 | 34 |
auth.realm.authenticate=http://localhost:8081/authenticate |
35 | 35 |
|
36 | 36 |
#default configuration user |
37 |
default_user_id = 2 |
|
37 |
default_user_id = 2 |
|
38 |
|
|
39 |
## oauth2 -> keycloak |
|
40 |
|
|
41 |
# localhost is here thanks to KC_HOSTNAME_URL property in the docker-compose. Otherwise, there should be docker service name. |
|
42 |
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9080/auth/realms/spade |
|
43 |
#spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:9080/auth/realms/spade/protocol/openid-connect/certs |
|
44 |
|
|
45 |
|
|
46 |
#keycloak.auth-server-url=http://localhost:9080/auth |
|
47 |
#keycloak.realm=spade |
|
48 |
#keycloak.resource=spade-client |
|
49 |
|
|
50 |
logging.level.org.springframework.security=debug |
Také k dispozici: Unified diff
keycloak in spade and spawn integration.