diff --git a/.idea/modules/sporttag-psa_main.iml b/.idea/modules/sporttag-psa_main.iml index 264083fa..86d56ac7 100644 --- a/.idea/modules/sporttag-psa_main.iml +++ b/.idea/modules/sporttag-psa_main.iml @@ -75,6 +75,8 @@ + + @@ -93,7 +95,6 @@ - @@ -130,6 +131,8 @@ + + @@ -159,7 +162,7 @@ - + @@ -168,11 +171,9 @@ - - @@ -181,7 +182,6 @@ - diff --git a/.idea/modules/sporttag-psa_test.iml b/.idea/modules/sporttag-psa_test.iml index 00aeb860..84fe3d5a 100644 --- a/.idea/modules/sporttag-psa_test.iml +++ b/.idea/modules/sporttag-psa_test.iml @@ -72,6 +72,8 @@ + + @@ -83,8 +85,8 @@ - + @@ -96,7 +98,6 @@ - @@ -136,6 +137,8 @@ + + @@ -176,7 +179,7 @@ - + @@ -187,11 +190,9 @@ - - @@ -201,7 +202,6 @@ - diff --git a/build.gradle b/build.gradle index fffab544..10637e03 100644 --- a/build.gradle +++ b/build.gradle @@ -124,6 +124,9 @@ dependencies { // https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-oauth2 compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-oauth2', version: '2.0.0.RELEASE' + // https://mvnrepository.com/artifact/org.springframework.security/spring-security-jwt + compile group: 'org.springframework.security', name: 'spring-security-jwt', version: '1.0.9.RELEASE' + // https://mvnrepository.com/artifact/org.passay/passay compile group: 'org.passay', name: 'passay', version: '1.3.1' diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/AuthorizationServerConfig.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/AuthorizationServerConfig.kt index 0b1fb466..fe3c63f3 100644 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/AuthorizationServerConfig.kt +++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/AuthorizationServerConfig.kt @@ -36,8 +36,11 @@ package ch.schulealtendorf.sporttagpsa.controller.config +import ch.schulealtendorf.sporttagpsa.business.setup.SetupManager import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Primary import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.oauth2.config.annotation.builders.ClientDetailsServiceBuilder import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer @@ -45,8 +48,10 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.A import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer +import org.springframework.security.oauth2.provider.token.DefaultTokenServices import org.springframework.security.oauth2.provider.token.TokenStore import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter /** * Configures OAuth 2 authorization server. @@ -58,7 +63,8 @@ import org.springframework.security.oauth2.provider.token.store.InMemoryTokenSto @EnableAuthorizationServer class AuthorizationServerConfig( @Qualifier("authenticationManagerBean") - private val authenticationManager: AuthenticationManager + private val authenticationManager: AuthenticationManager, + private val setupManager: SetupManager ): AuthorizationServerConfigurerAdapter() { override fun configure(security: AuthorizationServerSecurityConfigurer?) { @@ -96,11 +102,25 @@ class AuthorizationServerConfig( endpoints ?.tokenStore(tokenStore()) + ?.accessTokenConverter(tokenConverter()) ?.authenticationManager(authenticationManager) } + @Bean fun tokenStore(): TokenStore = InMemoryTokenStore() + @Bean + fun tokenConverter() = JwtAccessTokenConverter().apply { setSigningKey(setupManager.jwtSecret) } + + @Bean + @Primary + fun tokenService(): DefaultTokenServices { + return DefaultTokenServices().apply { + setTokenStore(tokenStore()) + setSupportRefreshToken(true) + } + } + private fun > ClientDetailsServiceBuilder.ClientBuilder.scopes(vararg values: PSAScope): ClientDetailsServiceBuilder.ClientBuilder { return scopes(*values.map { it.value }.toTypedArray()) } diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/JWTAuthenticationFilter.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/JWTAuthenticationFilter.kt deleted file mode 100644 index 6ae35202..00000000 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/JWTAuthenticationFilter.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2018 by Nicolas Märchy - * - * This file is part of Sporttag PSA. - * - * Sporttag PSA is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Sporttag PSA is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Sporttag PSA. If not, see . - * - * Diese Datei ist Teil von Sporttag PSA. - * - * Sporttag PSA ist Freie Software: Sie können es unter den Bedingungen - * der GNU General Public License, wie von der Free Software Foundation, - * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder späteren - * veröffentlichten Version, weiterverbreiten und/oder modifizieren. - * - * Sporttag PSA wird in der Hoffnung, dass es nützlich sein wird, aber - * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite - * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. - * Siehe die GNU General Public License für weitere Details. - * - * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem - * Programm erhalten haben. Wenn nicht, siehe . - * - * - */ - -package ch.schulealtendorf.sporttagpsa.controller.config - -import ch.schulealtendorf.sporttagpsa.business.user.UserLogin -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue -import io.jsonwebtoken.Jwts -import io.jsonwebtoken.SignatureAlgorithm -import org.joda.time.DateTime -import org.springframework.security.authentication.AuthenticationManager -import org.springframework.security.authentication.AuthenticationServiceException -import org.springframework.security.authentication.BadCredentialsException -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken -import org.springframework.security.core.Authentication -import org.springframework.security.core.AuthenticationException -import org.springframework.security.core.userdetails.User -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter -import org.springframework.stereotype.Component -import java.io.InputStream -import javax.servlet.FilterChain -import javax.servlet.http.HttpServletRequest -import javax.servlet.http.HttpServletResponse - -/** - * @author nmaerchy - * @since 0.0.1 - */ -class JWTAuthenticationFilter( - authManager: AuthenticationManager -): UsernamePasswordAuthenticationFilter() { - - init { - authenticationManager = authManager - } - - companion object { - const val SECRET = "MySecret" - const val EXPIRATION_TIME = 43200 // 12 hours - } - - override fun attemptAuthentication(request: HttpServletRequest?, response: HttpServletResponse?): Authentication { - - val body: InputStream = request?.inputStream?: throw BadCredentialsException("Username or password is invalid") - - val user = jacksonObjectMapper().readValue(body) - - return authenticationManager.authenticate( - UsernamePasswordAuthenticationToken( - user.username, - user.password, - listOf() - ) - ) - } - - override fun successfulAuthentication(request: HttpServletRequest?, response: HttpServletResponse?, chain: FilterChain?, authResult: Authentication?) { - - val token: String = Jwts.builder() - .setSubject((authResult?.principal as User).username) - .setExpiration(DateTime.now().plusSeconds(EXPIRATION_TIME).toDate()) - .signWith(SignatureAlgorithm.HS512, SECRET) - .compact() - - response?.addHeader("Authorization", "Bearer $token") - } -} \ No newline at end of file diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/JWTAuthorizationFilter.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/JWTAuthorizationFilter.kt deleted file mode 100644 index 88bd8e5a..00000000 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/JWTAuthorizationFilter.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2018 by Nicolas Märchy - * - * This file is part of Sporttag PSA. - * - * Sporttag PSA is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Sporttag PSA is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Sporttag PSA. If not, see . - * - * Diese Datei ist Teil von Sporttag PSA. - * - * Sporttag PSA ist Freie Software: Sie können es unter den Bedingungen - * der GNU General Public License, wie von der Free Software Foundation, - * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder späteren - * veröffentlichten Version, weiterverbreiten und/oder modifizieren. - * - * Sporttag PSA wird in der Hoffnung, dass es nützlich sein wird, aber - * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite - * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. - * Siehe die GNU General Public License für weitere Details. - * - * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem - * Programm erhalten haben. Wenn nicht, siehe . - * - * - */ - -package ch.schulealtendorf.sporttagpsa.controller.config - -import io.jsonwebtoken.Jwts -import org.springframework.security.authentication.AuthenticationManager -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken -import org.springframework.security.core.context.SecurityContextHolder -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter -import org.springframework.stereotype.Component -import java.util.* -import javax.servlet.FilterChain -import javax.servlet.http.HttpServletRequest -import javax.servlet.http.HttpServletResponse - -/** - * @author nmaerchy - * @since 0.0.1 - */ -class JWTAuthorizationFilter( - authManager: AuthenticationManager -): BasicAuthenticationFilter(authManager) { - - override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) { - - val token: String? = request.getHeader("Authorization") - - if (token == null || !token.startsWith("Bearer ")) { - chain.doFilter(request, response) - return - } - - SecurityContextHolder.getContext().authentication = getAuthentication(token).orElseGet { null } - chain.doFilter(request, response) - } - - private fun getAuthentication(token: String): Optional { - - val username: String = Jwts.parser() - ?.setSigningKey("MySecret") - ?.parseClaimsJws(token.replace("Bearer ", "")) - ?.body - ?.subject ?: return Optional.empty() - - return Optional.of(UsernamePasswordAuthenticationToken(username, null, listOf())) - } -} \ No newline at end of file diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/JWTHelper.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/JWTHelper.kt deleted file mode 100644 index f79b4b44..00000000 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/JWTHelper.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2018 by Nicolas Märchy - * - * This file is part of Sporttag PSA. - * - * Sporttag PSA is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Sporttag PSA is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Sporttag PSA. If not, see . - * - * Diese Datei ist Teil von Sporttag PSA. - * - * Sporttag PSA ist Freie Software: Sie können es unter den Bedingungen - * der GNU General Public License, wie von der Free Software Foundation, - * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder späteren - * veröffentlichten Version, weiterverbreiten und/oder modifizieren. - * - * Sporttag PSA wird in der Hoffnung, dass es nützlich sein wird, aber - * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite - * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. - * Siehe die GNU General Public License für weitere Details. - * - * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem - * Programm erhalten haben. Wenn nicht, siehe . - * - * - */ - -package ch.schulealtendorf.sporttagpsa.controller.config - -import io.jsonwebtoken.Claims -import io.jsonwebtoken.Jws -import io.jsonwebtoken.Jwts -import io.jsonwebtoken.SignatureAlgorithm -import org.joda.time.DateTime -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken -import javax.servlet.http.HttpServletRequest - -const val TOKEN_PREFIX: String = "Bearer " - -fun createJWT(request: HttpServletRequest, authentication: UsernamePasswordAuthenticationToken, secret: String): String { - - // help for the different claims: https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4 - return Jwts.builder() - .setIssuer(request.host()) - .setSubject(authentication.name) - .setAudience(request.getHeader("User-Agent")) - .claim("roles", authentication.authorities.map { it.authority }) - .setExpiration(DateTime.now().plusSeconds(JWTAuthenticationFilter.EXPIRATION_TIME).toDate()) - .signWith(SignatureAlgorithm.HS512, secret) - .compact() -} - -fun decodeJWT(request: HttpServletRequest, token: String, secret: String): Jws { - - return Jwts.parser() - ?.setSigningKey(secret) - ?.requireIssuer(request.host()) - ?.requireAudience(request.getHeader("User-Agent")) - ?.parseClaimsJws(token)!! -} - -private fun HttpServletRequest.host(): String { - return "$scheme://$serverName:$serverPort" -} diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/OAuth2ScopeConfig.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/OauthScopeConfig.kt similarity index 94% rename from src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/OAuth2ScopeConfig.kt rename to src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/OauthScopeConfig.kt index 84c31e37..7072bea0 100644 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/OAuth2ScopeConfig.kt +++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/OauthScopeConfig.kt @@ -43,14 +43,14 @@ import org.springframework.security.config.annotation.method.configuration.Globa import org.springframework.security.oauth2.provider.expression.OAuth2MethodSecurityExpressionHandler /** - * Configures method scope annotations. + * Configuration which enables method expression for oauth 2 scopes. * * @author nmaerchy * @since 2.0.0 */ @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) -class OAuth2ScopeConfig: GlobalMethodSecurityConfiguration() { +class OauthScopeConfig: GlobalMethodSecurityConfiguration() { override fun createExpressionHandler(): MethodSecurityExpressionHandler { return OAuth2MethodSecurityExpressionHandler() diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/ResourceServerConfig.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/ResourceServerConfig.kt index d0703195..a2ba5b54 100644 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/ResourceServerConfig.kt +++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/ResourceServerConfig.kt @@ -36,67 +36,56 @@ package ch.schulealtendorf.sporttagpsa.controller.config -import ch.schulealtendorf.sporttagpsa.business.setup.SetupManager -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.boot.autoconfigure.security.servlet.PathRequest -import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import org.springframework.security.authentication.AuthenticationManager -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.core.userdetails.UserDetailsService -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder -import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter - +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer +import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter +import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer +import org.springframework.security.oauth2.provider.token.DefaultTokenServices /** - * Security Configuration for the resource server resources and the authorization server resources. + * Configures the resource server. * - * @author nmaerchy - * @since 1.0.0 + * @author nmaerchy + * @since 2.0.0 */ @Configuration -@EnableWebSecurity +@EnableResourceServer class ResourceServerConfig( - @Qualifier("psa-user-service") - private val userDetailsService: UserDetailsService, - private val setupManager: SetupManager -): WebSecurityConfigurerAdapter() { - - @Autowired - fun configureGlobal(auth: AuthenticationManagerBuilder) { - auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()) - } + private val tokenServices: DefaultTokenServices +): ResourceServerConfigurerAdapter() { override fun configure(http: HttpSecurity?) { http - ?.csrf()?.disable() - ?.cors() - - ?.and() + ?.antMatcher("/api/**") ?.authorizeRequests() - ?.requestMatchers(PathRequest.toStaticResources().atCommonLocations())?.permitAll() - ?.antMatchers("/login", "/webjars/**", "/setup")?.permitAll() - ?.anyRequest()?.authenticated() - ?.and() - ?.formLogin()?.loginPage("/login")?.permitAll() + ?.antMatchers( + "/api/groups", + "/api/participation", + "/api/competitors", + "/api/competitor/**", + "/api/sports", + "/api/disciplines" + )?.hasRole("USER") + + ?.antMatchers( + "/api/group/**", + "/api/participant/**", + "/api/participants", + "/api/users", + "/api/user/**" + )?.hasRole("ADMIN") + + ?.anyRequest()?.authenticated() ?.and() - ?.addFilterBefore(SetupAuthorizationFilter(setupManager), BasicAuthenticationFilter::class.java) + ?.csrf()?.disable() + ?.cors() } - @Bean - @Qualifier("authenticationManagerBean") - override fun authenticationManager(): AuthenticationManager { - return super.authenticationManager() + override fun configure(resources: ResourceServerSecurityConfigurer?) { + resources?.tokenServices(tokenServices) } - - @Bean - fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder(4) } \ No newline at end of file diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/SecurityConfig.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/SecurityConfig.kt new file mode 100644 index 00000000..b6551b4f --- /dev/null +++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/config/SecurityConfig.kt @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2018 by Nicolas Märchy + * + * This file is part of Sporttag PSA. + * + * Sporttag PSA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Sporttag PSA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Sporttag PSA. If not, see . + * + * Diese Datei ist Teil von Sporttag PSA. + * + * Sporttag PSA ist Freie Software: Sie können es unter den Bedingungen + * der GNU General Public License, wie von der Free Software Foundation, + * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder späteren + * veröffentlichten Version, weiterverbreiten und/oder modifizieren. + * + * Sporttag PSA wird in der Hoffnung, dass es nützlich sein wird, aber + * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite + * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. + * Siehe die GNU General Public License für weitere Details. + * + * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem + * Programm erhalten haben. Wenn nicht, siehe . + * + * + */ + +package ch.schulealtendorf.sporttagpsa.controller.config + +import ch.schulealtendorf.sporttagpsa.business.setup.SetupManager +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.boot.autoconfigure.security.servlet.PathRequest +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.authentication.AuthenticationManager +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.core.userdetails.UserDetailsService +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter + + +/** + * Security Configuration for the resource server resources and the authorization server resources. + * + * @author nmaerchy + * @since 1.0.0 + */ +@Configuration +@EnableWebSecurity +class SecurityConfig( + @Qualifier("psa-user-service") + private val userDetailsService: UserDetailsService, + private val setupManager: SetupManager +): WebSecurityConfigurerAdapter() { + + @Autowired + fun configureGlobal(auth: AuthenticationManagerBuilder) { + auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()) + } + + override fun configure(http: HttpSecurity?) { + + http + ?.authorizeRequests() + ?.requestMatchers(PathRequest.toStaticResources().atCommonLocations())?.permitAll() + ?.antMatchers("/login", "/webjars/**", "/setup")?.permitAll() + ?.anyRequest()?.authenticated() + + ?.and() + ?.formLogin()?.loginPage("/login")?.permitAll() + + ?.and() + ?.addFilterBefore(SetupAuthorizationFilter(setupManager), BasicAuthenticationFilter::class.java) + } + + @Bean + @Qualifier("authenticationManagerBean") + override fun authenticationManager(): AuthenticationManager { + return super.authenticationManager() + } + + @Bean + fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder(4) +} \ No newline at end of file diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/competitor/CompetitorController.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/competitor/CompetitorController.kt index af655ceb..020be329 100644 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/competitor/CompetitorController.kt +++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/competitor/CompetitorController.kt @@ -54,6 +54,7 @@ import java.util.* * @since 0.0.1 */ @RestController +@RequestMapping("/api") class CompetitorController( private val competitorManager: CompetitorManager, private val resultCalculator: ResultCalculator diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/discipline/DisciplineController.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/discipline/DisciplineController.kt index 9a36aa0b..fa2801ef 100644 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/discipline/DisciplineController.kt +++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/discipline/DisciplineController.kt @@ -40,6 +40,7 @@ import ch.schulealtendorf.sporttagpsa.business.athletics.DisciplineManager import ch.schulealtendorf.sporttagpsa.model.Discipline import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController /** @@ -47,6 +48,7 @@ import org.springframework.web.bind.annotation.RestController * @since 2.0.0 */ @RestController +@RequestMapping("/api") class DisciplineController( private val disciplineManager: DisciplineManager ) { diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/group/GroupController.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/group/GroupController.kt index bed3587b..00245469 100644 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/group/GroupController.kt +++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/group/GroupController.kt @@ -42,10 +42,7 @@ import ch.schulealtendorf.sporttagpsa.controller.rest.NotFoundException import ch.schulealtendorf.sporttagpsa.model.Group import org.springframework.http.MediaType import org.springframework.security.access.prepost.PreAuthorize -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestParam -import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.* /** * Rest controller for {@link Group}. @@ -54,6 +51,7 @@ import org.springframework.web.bind.annotation.RestController * @since 2.0.0 */ @RestController +@RequestMapping("/api") class GroupController( private val groupManager: GroupManager ) { diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/ParticipantController.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/ParticipantController.kt index d0b2a255..95f074a8 100644 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/ParticipantController.kt +++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/ParticipantController.kt @@ -53,6 +53,7 @@ import javax.validation.Valid * @since 2.0.0 */ @RestController +@RequestMapping("/api") class ParticipantController( private val participantManager: ParticipantManager, private val participationManager: ParticipationManager, diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participation/ParticipationController.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participation/ParticipationController.kt index 39a02440..1908ac90 100644 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participation/ParticipationController.kt +++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participation/ParticipationController.kt @@ -43,16 +43,14 @@ import ch.schulealtendorf.sporttagpsa.controller.rest.json import ch.schulealtendorf.sporttagpsa.model.ParticipationStatus import org.springframework.http.MediaType import org.springframework.security.access.prepost.PreAuthorize -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PatchMapping -import org.springframework.web.bind.annotation.RequestBody -import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.* /** * @author nmaerchy * @since 2.0.0 */ @RestController +@RequestMapping("/api") class ParticipationController( private val participationManager: ParticipationManager ) { @@ -64,7 +62,7 @@ class ParticipationController( return json(status) } - @PreAuthorize("#oauth2.hasScope('participation')") + @PreAuthorize("#oauth2.hasScope('participation') and hasAuthority('ADMIN')") @PatchMapping("/participation") fun updateParticipation(@RequestBody participation: RestParticipationStatus) { diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/sport/SportController.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/sport/SportController.kt index 538133e9..576eefbc 100644 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/sport/SportController.kt +++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/sport/SportController.kt @@ -41,6 +41,7 @@ import ch.schulealtendorf.sporttagpsa.model.Sport import org.springframework.http.MediaType import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController /** @@ -48,6 +49,7 @@ import org.springframework.web.bind.annotation.RestController * @since 2.0.0 */ @RestController +@RequestMapping("/api") class SportController( private val sportManager: SportManager ) { diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/web/groupimport/GroupImportController.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/web/groupimport/GroupImportController.kt index 3623ddfc..88690f95 100644 --- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/web/groupimport/GroupImportController.kt +++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/web/groupimport/GroupImportController.kt @@ -51,6 +51,7 @@ import org.springframework.web.multipart.MultipartFile * @since 2.0.0 */ @Controller +@RequestMapping("/api") class GroupImportController( private val fileParser: GroupFileParser, private val groupManager: GroupManager