commit 997c4599e5fea48c100e5dc904c40f62d5131faa
Author: Petr Urban <urbanp@gapps.zcu.cz>
Date:   Tue Dec 19 15:41:22 2023 +0100

    keycloak in spade and spawn integration.

diff --git a/pom.xml b/pom.xml
index 79c7729..1444772 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
 	<parent>
 		<groupId>org.springframework.boot</groupId>
 		<artifactId>spring-boot-starter-parent</artifactId>
-		<version>2.4.4</version>
+		<version>2.7.18</version>
 		<relativePath/> <!-- lookup parent from repository -->
 	</parent>
 
@@ -77,6 +77,26 @@
 	</dependencyManagement>
 
 	<dependencies>
+
+
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
+			<version>2.7.5</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+			<version>2.7.5</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+			<version>3.13.0</version>
+		</dependency>
+
 		<dependency>
 			<groupId>org.projectlombok</groupId>
 			<artifactId>lombok</artifactId>
@@ -88,6 +108,7 @@
 			<artifactId>spring-boot-starter</artifactId>
 		</dependency>
 
+
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-test</artifactId>
@@ -95,18 +116,8 @@
 		</dependency>
 
 		<dependency>
-			<groupId>org.springframework.boot</groupId>
-			<artifactId>spring-boot-starter-web</artifactId>
-		</dependency>
-
-		<dependency>
-			<groupId>org.springframework.security</groupId>
-			<artifactId>spring-security-web</artifactId>
-		</dependency>
-
-		<dependency>
-			<groupId>mysql</groupId>
-			<artifactId>mysql-connector-java</artifactId>
+			<groupId>com.mysql</groupId>
+			<artifactId>mysql-connector-j</artifactId>
 			<scope>runtime</scope>
 		</dependency>
 
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/exception/CustomErrorController.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/exception/CustomErrorController.java
index 8446077..89c97c7 100644
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/exception/CustomErrorController.java
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/exception/CustomErrorController.java
@@ -64,9 +64,5 @@ public class CustomErrorController implements ErrorController {
         return errorPage;
     }
 
-    @Override
-    public String getErrorPath() {
-        return "/error";
-    }
 
 }
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/MainController.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/MainController.java
deleted file mode 100644
index 4b1da46..0000000
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/MainController.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package cz.zcu.fav.kiv.antipatterndetectionapp.v2.controller;
-
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-@RequestMapping("/v2")
-public class MainController {
-
-    @GetMapping(value = "/testCall", produces = "application/json")
-    public ResponseEntity<String> TestController() {
-        String response = "{\"response\": \"successfully called\"}";
-
-        return ResponseEntity.ok().body(response);
-    }
-
-}
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/UserController.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/UserController.java
index b36d8d6..c16cdd3 100644
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/UserController.java
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/UserController.java
@@ -24,89 +24,6 @@ import java.util.HashMap;
 @RequestMapping("v2/user")
 public class UserController {
 
-    @Autowired
-    private AuthenticationManager authenticationManager;
-
-    /**
-     * Service for work with user management
-     */
-    @Autowired
-    private UserService userService;
-
-    /**
-     * Service for login, logout and authenticate
-     */
-    @Autowired
-    private OAuthService aOuthService;
-
-    /**
-     * Method to register new user in the app
-     *
-     * @param user User who wants register in to the app
-     * @return message
-     */
-    @PostMapping(value = "/register")
-    public ResponseEntity<String> registerUser(@RequestBody User user) {
-        UserModelStatusCodes statusCode = userService.registerUser(user);
-        return getResponseEntity(statusCode, null);
-    }
-
-    /**
-     * Method to login user in to the app
-     *
-     * @param user User who wants to login in to the app
-     * @return message
-     */
-    @PostMapping(value = "/login")
-    public ResponseEntity<String> loginUser(@RequestBody User user) {
-        UserModelStatusCodes statusCode = userService.verifyUser(user);
-//        ResponseEntity<String> response = aOuthService.loginUser(user);
-
-        String jwtToken = null;
-        if (statusCode.getStatusCode() == 200) {
-            ResponseEntity<String> response = aOuthService.loginUser(user);
-            jwtToken = response.getBody();
-        }
-
-        return getResponseEntity(statusCode, jwtToken);
-    }
-
-    /**
-     * Method to logout user from the app
-     *
-     * @param user User who wants logout from the app
-     * @return message after logout
-     */
-    @PostMapping(value = "/logout")
-    public ResponseEntity<String> logoutUser(@RequestHeader HttpHeaders headers, @RequestBody User user) {
-        final String authHeader = headers.getFirst(HttpHeaders.AUTHORIZATION);
-        if(authHeader == null || !authHeader.startsWith("Bearer")){
-            //chyba
-        }
-        final String token = authHeader.substring(7);
-        user.setToken(token);
-        return aOuthService.logoutUser(user);
-    }
-
-    @GetMapping("/refresh")
-    public ResponseEntity<String> refreshToken(@RequestHeader HttpHeaders headers) {
-        final String authHeader = headers.getFirst(HttpHeaders.AUTHORIZATION);
-        if (authHeader == null || !authHeader.startsWith("Bearer")) {
-            return getResponseEntity(UserModelStatusCodes.USER_LOGIN_FAILED, UserModelStatusCodes.USER_LOGIN_FAILED.getLabel());
-        }
-        final String token = authHeader.substring(7);
-
-        String jwtToken = null;
-        ResponseEntity<String> response = aOuthService.refreshToken(token);
-
-        if (response.getStatusCode().is2xxSuccessful()) {
-            jwtToken = response.getBody();
-            return getResponseEntity(UserModelStatusCodes.TOKEN_REFRESHED, jwtToken);
-        }
-
-        return getResponseEntity(UserModelStatusCodes.TOKEN_EXPIRED, UserModelStatusCodes.TOKEN_EXPIRED.getLabel());
-
-    }
 
     /**
      * Method to create response
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/AuthConfiguration.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/AuthConfiguration.java
new file mode 100644
index 0000000..281d568
--- /dev/null
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/AuthConfiguration.java
@@ -0,0 +1,87 @@
+package cz.zcu.fav.kiv.antipatterndetectionapp.v2.security;
+
+import com.nimbusds.jose.jwk.source.JWKSource;
+import com.nimbusds.jose.jwk.source.RemoteJWKSet;
+import com.nimbusds.jwt.proc.JWTProcessor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.config.Customizer;
+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.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
+import org.springframework.security.oauth2.jwt.JwtDecoder;
+import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
+import org.springframework.security.web.SecurityFilterChain;
+
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JWEAlgorithm;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.jwk.JWKSet;
+import com.nimbusds.jose.jwk.KeyUse;
+import com.nimbusds.jose.jwk.RSAKey;
+import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
+import com.nimbusds.jose.jwk.source.JWKSource;
+import com.nimbusds.jose.jwk.source.RemoteJWKSet;
+import com.nimbusds.jose.proc.JWEDecryptionKeySelector;
+import com.nimbusds.jose.proc.JWEKeySelector;
+import com.nimbusds.jose.proc.JWSKeySelector;
+import com.nimbusds.jose.proc.JWSVerificationKeySelector;
+import com.nimbusds.jose.proc.SecurityContext;
+import com.nimbusds.jose.util.Base64URL;
+import com.nimbusds.jwt.proc.ConfigurableJWTProcessor;
+import com.nimbusds.jwt.proc.DefaultJWTProcessor;
+import com.nimbusds.jwt.proc.JWTProcessor;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.oauth2.jwt.JwtDecoder;
+import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.CorsConfigurationSource;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import java.net.URL;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.util.Arrays;
+
+import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;
+
+@EnableWebSecurity
+public class AuthConfiguration {
+    @Bean
+    public SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) throws Exception {
+        http
+                .cors()
+                .and()
+                .authorizeRequests(authz -> authz
+                        .antMatchers("/v2/app/metadata/**", "/v2/user/register").permitAll() // Allow all requests to /v2/app/metadata/**
+                        .antMatchers("/v2/**").hasAnyRole("spade_basic")
+                        .anyRequest().authenticated()
+                )
+                .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwtConfigurer -> jwtConfigurer.jwtAuthenticationConverter(new JwtAuthenticationTokenConverter())))
+                .sessionManagement(session -> session.sessionCreationPolicy(STATELESS));
+        return http.build();
+    }
+
+    @Bean
+    public WebMvcConfigurer corsConfigurer() {
+        return new WebMvcConfigurer() {
+            @Override
+            public void addCorsMappings(CorsRegistry registry) {
+                registry.addMapping("/**")
+                        .allowedMethods("GET", "POST", "OPTIONS", "PUT", "DELETE", "PATCH")
+                        .allowedHeaders("authorization", "content-type")
+                        .allowedOrigins("http://localhost:3000")
+                        .allowCredentials(true);
+            }
+        };
+    }
+
+}
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/JwtAuthenticationFilter.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/JwtAuthenticationFilter.java
deleted file mode 100644
index 3914200..0000000
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/JwtAuthenticationFilter.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package cz.zcu.fav.kiv.antipatterndetectionapp.v2.security;
-
-import cz.zcu.fav.kiv.antipatterndetectionapp.v2.config.SecurityBasics;
-import cz.zcu.fav.kiv.antipatterndetectionapp.v2.service.oauth.OAuthService;
-import org.springframework.http.*;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.HttpClientErrorException;
-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.Arrays;
-import java.util.Collections;
-
-@Component
-public class JwtAuthenticationFilter extends OncePerRequestFilter {
-
-    private final OAuthService oAuthService;
-
-    public JwtAuthenticationFilter(OAuthService oAuthService) {
-        this.oAuthService = oAuthService;
-    }
-
-    @Override
-    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
-            throws IOException, ServletException {
-
-        String authorizationHeader = request.getHeader("Authorization");
-        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
-//            chain.doFilter(request, response);
-            SecurityContextHolder.clearContext();
-            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-            response.getOutputStream().println("{\"message\" : \"Authentication failed\"}");
-            return;
-        }
-
-        try {
-            String token = authorizationHeader.replace("Bearer ", "");
-            ResponseEntity<String> responseEntity = oAuthService.authenticate(token);
-
-            UserDetails userDetails = User.builder()
-                        .username(responseEntity.getBody())
-                        .password("")
-                        .authorities(Collections.emptyList())
-                        .build();
-
-                Authentication auth = new UsernamePasswordAuthenticationToken(userDetails, token, userDetails.getAuthorities());
-                SecurityContextHolder.getContext().setAuthentication(auth);
-    /*
-            else {
-                SecurityContextHolder.clearContext();
-                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-                response.getOutputStream().println("{\"error\" : \"Token timed out!\"}");
-                return;
-            }*/
-        }
-        //4xx or 5xx http response from auth application
-        //basically copies the response from auth app and send it to client
-        catch (HttpClientErrorException e){
-            SecurityContextHolder.clearContext();
-            //read response body
-            String responseBody = e.getResponseBodyAsString();
-            response.setStatus(e.getStatusCode().value());
-            response.getOutputStream().println(responseBody);
-            return;
-        }
-
-        chain.doFilter(request, response);
-    }
-
-    @Override
-    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
-        String path = request.getRequestURI().substring(request.getContextPath().length());
-        return Arrays.stream(SecurityBasics.NO_AUTHORIZATION_NEEDED).anyMatch(path::startsWith);
-    }
-
-
-}
-
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/JwtAuthenticationTokenConverter.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/JwtAuthenticationTokenConverter.java
new file mode 100644
index 0000000..e67ad49
--- /dev/null
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/JwtAuthenticationTokenConverter.java
@@ -0,0 +1,47 @@
+package cz.zcu.fav.kiv.antipatterndetectionapp.v2.security;
+
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.security.oauth2.jwt.JwtClaimNames;
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
+import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class JwtAuthenticationTokenConverter implements Converter<Jwt, AbstractAuthenticationToken> {
+
+    private static final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
+    private String resourceId = "spade-client";
+    private String principalAttribute = "preferred_username";
+
+    @Override
+    public AbstractAuthenticationToken convert(Jwt jwt) {
+        Collection<GrantedAuthority> authorities =
+                Stream.concat(jwtGrantedAuthoritiesConverter.convert(jwt).stream(), extractResourceRoles(jwt).stream())
+                        .collect(Collectors.toSet());
+        String claimName = principalAttribute == null ? JwtClaimNames.SUB : principalAttribute;
+        return new JwtAuthenticationToken(jwt, authorities, jwt.getClaim(claimName));
+    }
+
+    private Collection<? extends GrantedAuthority> extractResourceRoles(Jwt jwt) {
+        Map<String, Object> resourceAccess = jwt.getClaim("resource_access");
+        Map<String, Object> resource;
+        Collection<String> resourceRoles;
+        if (resourceAccess == null
+                || (resource = (Map<String, Object>) resourceAccess.get(resourceId)) == null
+                || (resourceRoles = (Collection<String>) resource.get("roles")) == null) {
+            return Collections.emptySet();
+        }
+        return resourceRoles.stream()
+                .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
+                .collect(Collectors.toSet());
+    }
+
+}
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/WebSecurityConfig.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/WebSecurityConfig.java
deleted file mode 100644
index cb59ef2..0000000
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/security/WebSecurityConfig.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package cz.zcu.fav.kiv.antipatterndetectionapp.v2.security;
-
-import cz.zcu.fav.kiv.antipatterndetectionapp.v2.config.SecurityBasics;
-import cz.zcu.fav.kiv.antipatterndetectionapp.v2.service.oauth.AuthProvider;
-import cz.zcu.fav.kiv.antipatterndetectionapp.v2.service.oauth.OAuthService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.AuthenticationProvider;
-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.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-import org.springframework.security.config.http.SessionCreationPolicy;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.CorsConfigurationSource;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
-
-import java.util.Arrays;
-
-@Configuration
-@EnableWebSecurity(debug = true)
-public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
-
-    @Autowired
-    private UserDetailsService userService;
-
-    @Autowired
-    private JwtAuthenticationFilter jwtAuthenticationFilter;
-
-    @Autowired
-    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
-        auth.userDetailsService(userService);
-    }
-
-    @Bean
-    public AuthenticationProvider provider() {
-        return new AuthProvider(template());
-    }
-
-    @Bean
-    public RestTemplate template() {
-        return new RestTemplate();
-    }
-
-    @Bean
-    public UserDetailsService userDetailsService() {
-        return super.userDetailsService();
-    }
-
-    @Bean
-    public FilterRegistrationBean filterRegistrationBean(OAuthService oAuthService) {
-        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
-        filterRegistrationBean.setFilter(jwtAuthenticationFilter);
-        return filterRegistrationBean;
-    }
-
-    @Override
-    @Bean
-    public AuthenticationManager authenticationManagerBean() throws Exception {
-        return super.authenticationManagerBean();
-    }
-
-
-    @Override
-    protected void configure(HttpSecurity httpSecurity) throws Exception {
-        httpSecurity
-                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
-                .cors().configurationSource(corsConfigurationSource())
-                .and()
-                .csrf().disable()
-                .authorizeRequests()
-                .mvcMatchers(SecurityBasics.NO_AUTHORIZATION_NEEDED).permitAll()
-                .anyRequest().authenticated()
-                .and()
-                .sessionManagement()
-                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
-    }
-
-    @Bean
-    public CorsConfigurationSource corsConfigurationSource() {
-        CorsConfiguration configuration = new CorsConfiguration();
-        configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
-        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
-        configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
-        configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
-        configuration.setAllowCredentials(true);
-        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
-        source.registerCorsConfiguration("/**", configuration);
-        return source;
-    }
-
-}
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/AuthProvider.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/AuthProvider.java
index 7240326..870d8bd 100644
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/AuthProvider.java
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/AuthProvider.java
@@ -17,17 +17,16 @@ import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.stereotype.Service;
 import org.springframework.web.client.RestTemplate;
 
-@Service
 public class AuthProvider implements AuthenticationProvider {
 
     @Value("${auth.realm.authenticate}")
     private String auth_url;
 
-    private RestTemplate template;
+//    private RestTemplate template;
 
-    public AuthProvider(RestTemplate restTemplate){
-        this.template = restTemplate;
-    }
+//    public AuthProvider(RestTemplate restTemplate){
+//        this.template = restTemplate;
+//    }
 
 
     @Override
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/OAuthService.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/OAuthService.java
index 70ada33..19c7ebf 100644
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/OAuthService.java
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/OAuthService.java
@@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletRequest;
 
 public interface OAuthService {
     public ResponseEntity<String> authenticate(String token);
+    ResponseEntity<String> authenticate(HttpServletRequest request);
     public ResponseEntity<String> loginUser(User user);
     public ResponseEntity<String> logoutUser(User user);
 
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/OAuthServiceImpl.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/OAuthServiceImpl.java
index 448bbeb..7f28522 100644
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/OAuthServiceImpl.java
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/oauth/OAuthServiceImpl.java
@@ -4,12 +4,14 @@ import cz.zcu.fav.kiv.antipatterndetectionapp.v2.model.User;
 import cz.zcu.fav.kiv.antipatterndetectionapp.v2.service.user.UserService;
 import cz.zcu.fav.kiv.antipatterndetectionapp.v2.utils.RequestBuilder;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpRequest;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.stereotype.Service;
 
+import javax.servlet.http.HttpServletRequest;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
@@ -56,6 +58,11 @@ public class OAuthServiceImpl implements OAuthService, UserDetailsService {
         return requestBuilder.sendRequestResponse(AUTH_URL_AUTH, token);
     }
 
+    @Override
+    public ResponseEntity<String> authenticate(HttpServletRequest request) {
+        return requestBuilder.resendHttpRequest(request, AUTH_URL_AUTH);
+    }
+
     public ResponseEntity<String> loginUser(User user) {
         final String userName = user.getName();
 
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/utils/RequestBuilder.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/utils/RequestBuilder.java
index c57b79a..9dc425a 100644
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/utils/RequestBuilder.java
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/utils/RequestBuilder.java
@@ -3,16 +3,88 @@ package cz.zcu.fav.kiv.antipatterndetectionapp.v2.utils;
 import cz.zcu.fav.kiv.antipatterndetectionapp.v2.httpErrorHandler.CustomErrorHandler;
 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
 import org.springframework.stereotype.Component;
+import org.springframework.util.StreamUtils;
 import org.springframework.web.client.RestTemplate;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Enumeration;
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import org.springframework.http.*;
 
+import javax.servlet.http.HttpServletRequest;
+
 @Component
 public class RequestBuilder {
     private static Logger logger = Logger.getLogger(RequestBuilder.class.getName());
 
+    public ResponseEntity<String> resendHttpRequest(HttpServletRequest request, String authenticationUrl) {
+        try {
+            // Extract request method, headers, and body from the original request
+            String method = request.getMethod();
+            HttpHeaders headers = extractHeaders(request);
+            headers.add(HttpHeaders.HOST, "http://localhost:8080");
+            String body = extractBody(request);
+
+            // Create a new RestTemplate instance
+            RestTemplate restTemplate = new RestTemplate();
+            restTemplate.setErrorHandler(new CustomErrorHandler());
+            restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
+
+            // Set Authorization header with the provided token
+//            headers.set(HttpHeaders.AUTHORIZATION, "Bearer " + token);
+
+            // Create an HttpEntity with headers and body
+            HttpEntity<String> entity = new HttpEntity<>(body, headers);
+
+            // Determine the appropriate exchange method based on the original request method
+            ResponseEntity<String> response;
+            if ("GET".equalsIgnoreCase(method)) {
+                response = restTemplate.exchange(authenticationUrl, HttpMethod.GET, entity, String.class);
+            } else if ("POST".equalsIgnoreCase(method)) {
+                response = restTemplate.exchange(authenticationUrl, HttpMethod.POST, entity, String.class);
+            } else {
+                // Handle other HTTP methods as needed
+                // ...
+
+                // For simplicity, in this example, we assume other methods are handled as POST requests
+                response = restTemplate.exchange(authenticationUrl, HttpMethod.POST, entity, String.class);
+            }
+
+            logger.log(Level.FINE, "Successfully resent HTTP request to: " + authenticationUrl);
+            return response;
+        } catch (Exception e) {
+            logger.log(Level.SEVERE, "Error resending HTTP request", e);
+            // Handle the exception as needed
+            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error resending HTTP request");
+        }
+    }
+
+    // Helper method to extract headers from HttpServletRequest
+    private HttpHeaders extractHeaders(HttpServletRequest request) {
+        HttpHeaders headers = new HttpHeaders();
+        Enumeration<String> headerNames = request.getHeaderNames();
+        while (headerNames.hasMoreElements()) {
+            String headerName = headerNames.nextElement();
+            Enumeration<String> headerValues = request.getHeaders(headerName);
+            while (headerValues.hasMoreElements()) {
+                String headerValue = headerValues.nextElement();
+                headers.add(headerName, headerValue);
+            }
+        }
+        return headers;
+    }
+
+    // Helper method to extract body from HttpServletRequest
+    private String extractBody(HttpServletRequest request) throws IOException {
+        try (InputStream inputStream = request.getInputStream()) {
+            return StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
+        }
+    }
+
     public ResponseEntity<String> sendRequestResponse(String url, Map<String, Object> body) {
         RestTemplate restTemplate = new RestTemplate();
         restTemplate.setErrorHandler(new CustomErrorHandler());
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 633a101..f2e3c05 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -12,7 +12,7 @@ spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
 # mssql database connection:
 spring.second-datasource.jdbc-url=jdbc:sqlserver://localhost:1433;databaseName=authspade;encrypt=true;trustServerCertificate=true
 spring.second-datasource.username=test
-spring.second-datasource.password=
+spring.second-datasource.password=test
 spring.second-datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
 
 # admin account username and password:
@@ -34,4 +34,17 @@ auth.realm.logout=http://localhost:8081/logout
 auth.realm.authenticate=http://localhost:8081/authenticate
 
 #default configuration user
-default_user_id = 2
\ No newline at end of file
+default_user_id = 2
+
+## oauth2 -> keycloak
+
+# localhost is here thanks to KC_HOSTNAME_URL property in the docker-compose. Otherwise, there should be docker service name.
+spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9080/auth/realms/spade
+#spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:9080/auth/realms/spade/protocol/openid-connect/certs
+
+
+#keycloak.auth-server-url=http://localhost:9080/auth
+#keycloak.realm=spade
+#keycloak.resource=spade-client
+
+logging.level.org.springframework.security=debug
\ No newline at end of file
