diff --git a/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java new file mode 100644 index 0000000..10b0d45 --- /dev/null +++ b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfig.java @@ -0,0 +1,20 @@ +package org.kickerelo.kickerelo.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.security.oauth2.client.JdbcOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; + +@Profile("prod") +@Configuration +public class SecurityConfig { + @Bean + public OAuth2AuthorizedClientService authorizedClientService( + JdbcTemplate jdbcTemplate, + ClientRegistrationRepository clientRegistrationRepository) { + return new JdbcOAuth2AuthorizedClientService(jdbcTemplate, clientRegistrationRepository); + } +} diff --git a/src/main/java/org/kickerelo/kickerelo/config/SecurityConfiguration.java b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfiguration.java index 88f109b..8526411 100644 --- a/src/main/java/org/kickerelo/kickerelo/config/SecurityConfiguration.java +++ b/src/main/java/org/kickerelo/kickerelo/config/SecurityConfiguration.java @@ -2,31 +2,77 @@ package org.kickerelo.kickerelo.config; import java.security.SecureRandom; import java.util.Base64; + +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import com.vaadin.flow.spring.security.VaadinWebSecurity; +import org.springframework.security.oauth2.client.*; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; +import org.springframework.security.web.SecurityFilterChain; @Profile("prod") @Configuration -class SecurityConfiguration extends VaadinWebSecurity { +class SecurityConfiguration { + + private final OAuth2AuthorizedClientService authorizedClientService; + + // Inject the persistent authorized client service we configured previously + public SecurityConfiguration(OAuth2AuthorizedClientService authorizedClientService) { + this.authorizedClientService = authorizedClientService; + } private static String rememberMeSecret = null; - @Override protected void configure(HttpSecurity http) throws Exception { if (rememberMeSecret == null) rememberMeSecret = generateSecret(); http.authorizeHttpRequests(auth -> auth .requestMatchers("/app/admin/**", "/app/admin", "/app/app/admin/**", "/app/app/admin").hasAuthority("Kicker Admin") .anyRequest().permitAll()) - .rememberMe(rememberMe -> rememberMe.key(rememberMeSecret)) .oauth2Login(org.springframework.security.config.Customizer.withDefaults()) .logout(logout -> logout.logoutSuccessUrl("/")) .csrf(csrf -> csrf.disable()); } + + @Bean + public OAuth2AuthorizedClientManager authorizedClientManager( + ClientRegistrationRepository clientRegistrationRepository, + OAuth2AuthorizedClientRepository authorizedClientRepository) { + + OAuth2AuthorizedClientProvider authorizedClientProvider = + OAuth2AuthorizedClientProviderBuilder.builder() + .authorizationCode() + .refreshToken() + .clientCredentials() + .build(); + + DefaultOAuth2AuthorizedClientManager authorizedClientManager = + new DefaultOAuth2AuthorizedClientManager( + clientRegistrationRepository, authorizedClientRepository); + authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); + + return authorizedClientManager; + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.authorizeHttpRequests(auth -> auth + .requestMatchers("/app/admin/**", "/app/admin", "/app/app/admin/**", "/app/app/admin").hasAuthority("Kicker Admin") + .anyRequest().permitAll()) + .oauth2Login(org.springframework.security.config.Customizer.withDefaults()) + .logout(logout -> logout.logoutSuccessUrl("/")) + .csrf(csrf -> csrf.disable()); + + return http.build(); + } + private String generateSecret() { SecureRandom random = new SecureRandom(); byte[] bytes = new byte[24]; diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index ca0774f..a3dc2fa 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -13,7 +13,7 @@ spring.jpa.open-in-view=false # == OIDC Configuration == spring.security.oauth2.client.registration.oidc.client-id=${OIDC_CLIENT_ID} spring.security.oauth2.client.registration.oidc.client-secret=${OIDC_CLIENT_SECRET} -spring.security.oauth2.client.registration.oidc.scope=openid,email,profile +spring.security.oauth2.client.registration.oidc.scope=openid,email,profile,offline_access spring.security.oauth2.client.registration.oidc.redirect-uri=${OIDC_REDIRECT_URI} spring.security.oauth2.client.provider.oidc.jwk-set-uri=${OIDC_JWK_SET_URI} spring.security.oauth2.client.provider.oidc.issuer-uri=${OIDC_ISSUER_URI} diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index c056b5d..6dbe2e1 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -55,4 +55,19 @@ ALTER TABLE ergebnis2vs2 ADD CONSTRAINT FK_ERGEBNIS2VS2_ON_VERLIERER_HINTEN FOREIGN KEY (verlierer_hinten) REFERENCES spieler (id); ALTER TABLE ergebnis2vs2 - ADD CONSTRAINT FK_ERGEBNIS2VS2_ON_VERLIERER_VORN FOREIGN KEY (verlierer_vorn) REFERENCES spieler (id); \ No newline at end of file + ADD CONSTRAINT FK_ERGEBNIS2VS2_ON_VERLIERER_VORN FOREIGN KEY (verlierer_vorn) REFERENCES spieler (id); + + +CREATE TABLE oauth2_authorized_client ( + client_registration_id varchar(100) NOT NULL, + principal_name varchar(200) NOT NULL, + access_token_type varchar(100) NOT NULL, + access_token_value blob NOT NULL, + access_token_issued_at timestamp NOT NULL, + access_token_expires_at timestamp NOT NULL, + access_token_scopes varchar(1000) DEFAULT NULL, + refresh_token_value blob DEFAULT NULL, + refresh_token_issued_at timestamp DEFAULT NULL, + created_at timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, + PRIMARY KEY (client_registration_id, principal_name) +); \ No newline at end of file