diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/Constants.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/Constants.kt index 6286baa..6478c24 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/Constants.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/Constants.kt @@ -37,9 +37,9 @@ object Constants { const val RECIPE_IMAGES = "$IMAGES/recipes" } - object HeaderNames { - const val ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers" - const val AUTHORIZATION = "Authorization" + object JwtType { + const val USER = 0 + const val GROUP = 1 } object ModelNames { diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/GroupTokenAuthenticationProvider.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/GroupTokenAuthenticationProvider.kt index d865f45..f0bf5fc 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/GroupTokenAuthenticationProvider.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/GroupTokenAuthenticationProvider.kt @@ -1,30 +1,56 @@ package dev.fyloz.colorrecipesexplorer.config.security +import dev.fyloz.colorrecipesexplorer.dtos.account.GroupTokenDto import dev.fyloz.colorrecipesexplorer.dtos.account.UserDetails import dev.fyloz.colorrecipesexplorer.exception.NotFoundException import dev.fyloz.colorrecipesexplorer.logic.account.GroupTokenLogic +import mu.KotlinLogging import org.springframework.security.authentication.AuthenticationProvider 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 java.util.* class GroupTokenAuthenticationProvider(private val groupTokenLogic: GroupTokenLogic) : AuthenticationProvider { + private val logger = KotlinLogging.logger {} + override fun authenticate(authentication: Authentication): Authentication { val groupAuthenticationToken = authentication as GroupAuthenticationToken - val groupToken = retrieveGroupToken(groupAuthenticationToken.id) + + val groupToken = try { + retrieveGroupToken(groupAuthenticationToken.id) + } catch (e: AuthenticationException) { + logger.debug(e.message) + throw e + } val userDetails = - UserDetails(groupToken.id.toString(), groupToken.name, "", groupToken.group, groupToken.group.permissions) + UserDetails( + groupToken.id.toString(), + groupToken.name, + "", + groupToken.group, + groupToken.group.permissions, + true + ) return UsernamePasswordAuthenticationToken(userDetails, null, userDetails.authorities) } override fun supports(authentication: Class<*>) = authentication.isAssignableFrom(GroupAuthenticationToken::class.java) - private fun retrieveGroupToken(id: UUID) = try { - groupTokenLogic.getById(id) - } catch (_: NotFoundException) { - throw BadCredentialsException("Failed to find group token with id '$id'") + private fun retrieveGroupToken(id: UUID): GroupTokenDto { + val groupToken = try { + groupTokenLogic.getById(id) + } catch (_: NotFoundException) { + throw BadCredentialsException("Failed to find group token with id '$id'") + } + + if (groupTokenLogic.isDisabled(groupToken.id.toString())) { + throw BadCredentialsException("Group token '${groupToken.id}' is disabled") + } + + return groupToken } -} \ No newline at end of file +} diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/SecurityConfig.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/SecurityConfig.kt index a9fe540..fdb2984 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/SecurityConfig.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/SecurityConfig.kt @@ -101,7 +101,7 @@ abstract class BaseSecurityConfig( BasicAuthenticationFilter::class.java ) .addFilter( - JwtAuthorizationFilter(jwtLogic, authenticationManager()) + JwtAuthorizationFilter(jwtLogic, groupTokenLogic, authManager) ) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/filters/JwtAuthorizationFilter.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/filters/JwtAuthorizationFilter.kt index 52f5a43..cb7e30c 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/filters/JwtAuthorizationFilter.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/security/filters/JwtAuthorizationFilter.kt @@ -1,13 +1,16 @@ package dev.fyloz.colorrecipesexplorer.config.security.filters import dev.fyloz.colorrecipesexplorer.Constants +import dev.fyloz.colorrecipesexplorer.dtos.account.UserJwt +import dev.fyloz.colorrecipesexplorer.logic.account.GroupTokenLogic import dev.fyloz.colorrecipesexplorer.logic.account.JwtLogic -import dev.fyloz.colorrecipesexplorer.logic.account.UserJwt import dev.fyloz.colorrecipesexplorer.utils.parseBearer import io.jsonwebtoken.ExpiredJwtException +import mu.KotlinLogging import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.Authentication +import org.springframework.security.core.AuthenticationException import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.web.authentication.www.BasicAuthenticationFilter import org.springframework.web.util.WebUtils @@ -17,10 +20,11 @@ import javax.servlet.http.HttpServletResponse class JwtAuthorizationFilter( private val jwtLogic: JwtLogic, + private val groupTokenLogic: GroupTokenLogic, authenticationManager: AuthenticationManager ) : BasicAuthenticationFilter(authenticationManager) { override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) { - val authorizationCookie = WebUtils.getCookie(request, Constants.HeaderNames.AUTHORIZATION) + val authorizationCookie = WebUtils.getCookie(request, Constants.CookieNames.AUTHORIZATION) // If there is no authorization cookie, the user is not authenticated if (authorizationCookie == null) { @@ -30,6 +34,8 @@ class JwtAuthorizationFilter( val authorizationToken = authorizationCookie.value if (!isJwtValid(authorizationToken)) { + logger.debug("Received request with invalid ${Constants.CookieNames.AUTHORIZATION} cookie") + chain.doFilter(request, response) return } @@ -47,8 +53,14 @@ class JwtAuthorizationFilter( val jwt = parseBearer(authorizationToken) val user = jwtLogic.parseUserJwt(jwt) + if (user.isGroup && groupTokenLogic.isDisabled(user.id)) { + logger.debug("Rejected authorization for disabled group token '${user.id}'") + return null + } + getAuthentication(user) } catch (_: ExpiredJwtException) { + logger.debug("Rejected authorization for expired JWT") null } } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/dtos/account/GroupTokenDto.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/dtos/account/GroupTokenDto.kt index 8708ed2..6277fdc 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/dtos/account/GroupTokenDto.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/dtos/account/GroupTokenDto.kt @@ -8,7 +8,7 @@ data class GroupTokenDto( val name: String, - val isValid: Boolean, + val enabled: Boolean, val group: GroupDto ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/dtos/account/UserDto.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/dtos/account/UserDto.kt index 1dbb98a..6216a76 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/dtos/account/UserDto.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/dtos/account/UserDto.kt @@ -5,7 +5,7 @@ import dev.fyloz.colorrecipesexplorer.Constants import dev.fyloz.colorrecipesexplorer.SpringUserDetails import dev.fyloz.colorrecipesexplorer.dtos.EntityDto import dev.fyloz.colorrecipesexplorer.model.account.Permission -import dev.fyloz.colorrecipesexplorer.model.account.toAuthority +import org.springframework.security.core.GrantedAuthority import java.time.LocalDateTime import javax.validation.constraints.NotBlank import javax.validation.constraints.Size @@ -67,12 +67,15 @@ data class UserUpdateDto( data class UserLoginRequestDto(val id: Long, val password: String) +data class UserJwt(val id: String, val authorities: Collection, val isGroup: Boolean) + class UserDetails( val id: String, private val username: String, private val password: String, val group: GroupDto?, - val permissions: Collection + val permissions: Collection, + val isGroup: Boolean = false ) : SpringUserDetails { constructor(user: UserDto) : this(user.id.toString(), user.fullName, user.password, user.group, user.permissions) @@ -94,4 +97,4 @@ data class UserLoginResponse( val groupId: Long?, val groupName: String?, val permissions: Collection -) \ No newline at end of file +) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/GroupTokenLogic.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/GroupTokenLogic.kt index da5d927..f689530 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/GroupTokenLogic.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/GroupTokenLogic.kt @@ -8,13 +8,17 @@ import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.exception.NotFoundException import dev.fyloz.colorrecipesexplorer.logic.BaseLogic import dev.fyloz.colorrecipesexplorer.service.account.GroupTokenService -import java.util.UUID +import java.util.* +import javax.annotation.PostConstruct interface GroupTokenLogic { + fun isDisabled(id: String): Boolean fun getAll(): Collection fun getById(id: String): GroupTokenDto fun getById(id: UUID): GroupTokenDto fun save(dto: GroupTokenSaveDto): GroupTokenDto + fun enable(id: String): GroupTokenDto + fun disable(id: String): GroupTokenDto fun deleteById(id: String) } @@ -24,30 +28,50 @@ class DefaultGroupTokenLogic(private val service: GroupTokenService, private val private val typeName = Constants.ModelNames.GROUP_TOKEN private val typeNameLowerCase = typeName.lowercase() - override fun getAll() = service.getAll() + private val enabledTokensCache = hashSetOf() + @PostConstruct + fun initEnabledTokensCache() { + val tokensIds = getAll().filter { it.enabled }.map { it.id.toString() } + enabledTokensCache.addAll(tokensIds) + } + + override fun isDisabled(id: String) = !enabledTokensCache.contains(id) + override fun getAll() = service.getAll() override fun getById(id: String) = getById(UUID.fromString(id)) - override fun getById(id: UUID) = - service.getById(id) ?: throw notFoundException(value = id) + override fun getById(id: UUID) = service.getById(id) ?: throw notFoundException(value = id) override fun save(dto: GroupTokenSaveDto): GroupTokenDto { throwIfNameAlreadyExists(dto.name) val token = GroupTokenDto( - generateUniqueUUIDForName(dto.name), - dto.name, - true, - groupLogic.getById(dto.groupId) + generateUniqueUUIDForName(dto.name), dto.name, true, groupLogic.getById(dto.groupId) ) - return service.save(token) + val savedToken = service.save(token) + enabledTokensCache.add(savedToken.id.toString()) + + return savedToken + } + + override fun enable(id: String) = setEnabled(id, true).also { + enabledTokensCache.add(id) + } + + override fun disable(id: String) = setEnabled(id, false).also { + enabledTokensCache.remove(id) } override fun deleteById(id: String) { + enabledTokensCache.remove(id) service.deleteById(UUID.fromString(id)) } + private fun setEnabled(id: String, enabled: Boolean) = with(getById(id)) { + service.save(this.copy(enabled = enabled)) + } + private fun generateUniqueUUIDForName(name: String): UUID { var id = generateUUIDForName(name) @@ -59,8 +83,7 @@ class DefaultGroupTokenLogic(private val service: GroupTokenService, private val return id } - private fun generateUUIDForName(name: String) = - UUID.nameUUIDFromBytes(name.toByteArray()) + private fun generateUUIDForName(name: String) = UUID.nameUUIDFromBytes(name.toByteArray()) private fun throwIfNameAlreadyExists(name: String) { if (service.existsByName(name)) { diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/JwtLogic.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/JwtLogic.kt index b2b6c38..4b0a971 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/JwtLogic.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/JwtLogic.kt @@ -4,14 +4,13 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import dev.fyloz.colorrecipesexplorer.config.properties.CreSecurityProperties import dev.fyloz.colorrecipesexplorer.dtos.account.UserDetails +import dev.fyloz.colorrecipesexplorer.dtos.account.UserJwt import dev.fyloz.colorrecipesexplorer.model.account.Permission -import dev.fyloz.colorrecipesexplorer.model.account.toAuthority import dev.fyloz.colorrecipesexplorer.utils.base64encode import dev.fyloz.colorrecipesexplorer.utils.toDate import io.jsonwebtoken.Jwts import io.jsonwebtoken.jackson.io.JacksonDeserializer import io.jsonwebtoken.jackson.io.JacksonSerializer -import org.springframework.security.core.GrantedAuthority import org.springframework.stereotype.Service import java.time.Instant import java.util.* @@ -41,11 +40,15 @@ class DefaultJwtLogic( securityProperties.jwtSecret.base64encode() } + private val permissionsById = Permission.values() + .associateBy { it.id } + // Must be a new instance every time, or data from the last token will still be there - private val jwtBuilder get() = - Jwts.builder() - .serializeToJsonWith(JacksonSerializer>(objectMapper)) - .signWith(secretKey) + private val jwtBuilder + get() = + Jwts.builder() + .serializeToJsonWith(JacksonSerializer>(objectMapper)) + .signWith(secretKey) private val jwtParser by lazy { Jwts.parserBuilder() @@ -54,12 +57,17 @@ class DefaultJwtLogic( .build() } - override fun buildUserJwt(userDetails: UserDetails): String = - jwtBuilder + override fun buildUserJwt(userDetails: UserDetails): String { + val permissionsIds = userDetails.permissions.map { it.id } + val type = if (userDetails.isGroup) JWT_TYPE_GROUP else JWT_TYPE_USER + + return jwtBuilder .setSubject(userDetails.id) .setExpiration(getCurrentExpirationDate()) - .claim(JWT_CLAIM_PERMISSIONS, objectMapper.writeValueAsString(userDetails.permissions)) + .claim(JWT_CLAIM_PERMISSIONS, objectMapper.writeValueAsString(permissionsIds)) + .claim(JWT_CLAIM_TYPE, type) .compact() + } override fun buildGroupTokenIdJwt(groupTokenId: UUID): String = jwtBuilder @@ -70,13 +78,17 @@ class DefaultJwtLogic( val parsedJwt = jwtParser.parseClaimsJws(jwt) val serializedPermissions = parsedJwt.body.get(JWT_CLAIM_PERMISSIONS, String::class.java) - val permissions = objectMapper.readValue>(serializedPermissions) + val permissionsIds = objectMapper.readValue>(serializedPermissions) + val permissions = permissionsIds.map { permissionsById[it]!! } + + val type = parsedJwt.body[JWT_CLAIM_TYPE] as Int + val isGroup = type == JWT_TYPE_GROUP val authorities = permissions .map { it.toAuthority() } .toMutableList() - return UserJwt(parsedJwt.body.subject, authorities) + return UserJwt(parsedJwt.body.subject, authorities, isGroup) } override fun parseGroupTokenIdJwt(jwt: String): UUID { @@ -90,8 +102,10 @@ class DefaultJwtLogic( .toDate() companion object { - private const val JWT_CLAIM_PERMISSIONS = "permissions" + private const val JWT_CLAIM_PERMISSIONS = "perms" + private const val JWT_CLAIM_TYPE = "type" + + private const val JWT_TYPE_USER = 0 + private const val JWT_TYPE_GROUP = 1 } } - -data class UserJwt(val id: String, val authorities: Collection) \ No newline at end of file diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/UserLogic.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/UserLogic.kt index 6725b2c..3916d89 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/UserLogic.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/logic/account/UserLogic.kt @@ -114,7 +114,7 @@ class DefaultUserLogic( } override fun logout(request: HttpServletRequest) { - val authorizationCookie = WebUtils.getCookie(request, Constants.HeaderNames.AUTHORIZATION) + val authorizationCookie = WebUtils.getCookie(request, Constants.CookieNames.AUTHORIZATION) if (authorizationCookie != null) { val authorizationToken = authorizationCookie.value if (authorizationToken != null && authorizationToken.startsWith("Bearer")) { diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/account/Permission.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/account/Permission.kt index abd2fb0..ecc0928 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/account/Permission.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/account/Permission.kt @@ -4,32 +4,34 @@ import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority enum class Permission( - val impliedPermissions: List = listOf(), + val id: Int, + private val impliedPermissions: List = listOf(), val deprecated: Boolean = false ) { - READ_FILE, - WRITE_FILE(listOf(READ_FILE)), + READ_FILE(0), + WRITE_FILE(1, listOf(READ_FILE)), - VIEW_RECIPES(listOf(READ_FILE)), - VIEW_CATALOG(listOf(READ_FILE)), - VIEW_USERS, + VIEW_RECIPES(2, listOf(READ_FILE)), + VIEW_CATALOG(3, listOf(READ_FILE)), + VIEW_USERS(4), - EDIT_RECIPES_PUBLIC_DATA(listOf(VIEW_RECIPES)), - EDIT_RECIPES(listOf(EDIT_RECIPES_PUBLIC_DATA, WRITE_FILE)), - EDIT_MATERIALS(listOf(VIEW_CATALOG, WRITE_FILE)), - EDIT_MATERIAL_TYPES(listOf(VIEW_CATALOG)), - EDIT_COMPANIES(listOf(VIEW_CATALOG)), - EDIT_USERS(listOf(VIEW_USERS)), - EDIT_CATALOG(listOf(EDIT_MATERIALS, EDIT_MATERIAL_TYPES, EDIT_COMPANIES)), + EDIT_RECIPES_PUBLIC_DATA(5, listOf(VIEW_RECIPES)), + EDIT_RECIPES(6, listOf(EDIT_RECIPES_PUBLIC_DATA, WRITE_FILE)), + EDIT_MATERIALS(7, listOf(VIEW_CATALOG, WRITE_FILE)), + EDIT_MATERIAL_TYPES(8, listOf(VIEW_CATALOG)), + EDIT_COMPANIES(9, listOf(VIEW_CATALOG)), + EDIT_USERS(10, listOf(VIEW_USERS)), + EDIT_CATALOG(11, listOf(EDIT_MATERIALS, EDIT_MATERIAL_TYPES, EDIT_COMPANIES)), - VIEW_TOUCH_UP_KITS, - EDIT_TOUCH_UP_KITS(listOf(VIEW_TOUCH_UP_KITS)), + VIEW_TOUCH_UP_KITS(12), + EDIT_TOUCH_UP_KITS(13, listOf(VIEW_TOUCH_UP_KITS)), - PRINT_MIXES(listOf(VIEW_RECIPES)), - ADD_TO_INVENTORY(listOf(VIEW_CATALOG)), - DEDUCT_FROM_INVENTORY(listOf(VIEW_RECIPES)), + PRINT_MIXES(14, listOf(VIEW_RECIPES)), + ADD_TO_INVENTORY(15, listOf(VIEW_CATALOG)), + DEDUCT_FROM_INVENTORY(16, listOf(VIEW_RECIPES)), ADMIN( + 17, listOf( EDIT_RECIPES, EDIT_CATALOG, @@ -44,58 +46,58 @@ enum class Permission( ), // deprecated permissions - VIEW_RECIPE(listOf(VIEW_RECIPES), true), - VIEW_MATERIAL(listOf(VIEW_CATALOG), true), - VIEW_MATERIAL_TYPE(listOf(VIEW_CATALOG), true), - VIEW_COMPANY(listOf(VIEW_CATALOG), true), - VIEW(listOf(VIEW_RECIPES, VIEW_CATALOG), true), - VIEW_EMPLOYEE(listOf(VIEW_USERS), true), - VIEW_EMPLOYEE_GROUP(listOf(VIEW_USERS), true), + VIEW_RECIPE(101, listOf(VIEW_RECIPES), true), + VIEW_MATERIAL(102, listOf(VIEW_CATALOG), true), + VIEW_MATERIAL_TYPE(103, listOf(VIEW_CATALOG), true), + VIEW_COMPANY(104, listOf(VIEW_CATALOG), true), + VIEW(105, listOf(VIEW_RECIPES, VIEW_CATALOG), true), + VIEW_EMPLOYEE(106, listOf(VIEW_USERS), true), + VIEW_EMPLOYEE_GROUP(107, listOf(VIEW_USERS), true), - EDIT_RECIPE(listOf(EDIT_RECIPES), true), - EDIT_MATERIAL(listOf(EDIT_MATERIALS), true), - EDIT_MATERIAL_TYPE(listOf(EDIT_MATERIAL_TYPES), true), - EDIT_COMPANY(listOf(EDIT_COMPANIES), true), - EDIT(listOf(EDIT_RECIPES, EDIT_CATALOG), true), - EDIT_EMPLOYEE(listOf(EDIT_USERS), true), - EDIT_EMPLOYEE_PASSWORD(listOf(EDIT_USERS), true), - EDIT_EMPLOYEE_GROUP(listOf(EDIT_USERS), true), + EDIT_RECIPE(108, listOf(EDIT_RECIPES), true), + EDIT_MATERIAL(109, listOf(EDIT_MATERIALS), true), + EDIT_MATERIAL_TYPE(110, listOf(EDIT_MATERIAL_TYPES), true), + EDIT_COMPANY(111, listOf(EDIT_COMPANIES), true), + EDIT(112, listOf(EDIT_RECIPES, EDIT_CATALOG), true), + EDIT_EMPLOYEE(113, listOf(EDIT_USERS), true), + EDIT_EMPLOYEE_PASSWORD(114, listOf(EDIT_USERS), true), + EDIT_EMPLOYEE_GROUP(115, listOf(EDIT_USERS), true), - REMOVE_FILE(listOf(WRITE_FILE), true), - GENERATE_TOUCH_UP_KIT(listOf(VIEW_TOUCH_UP_KITS), true), + REMOVE_FILE(116, listOf(WRITE_FILE), true), + GENERATE_TOUCH_UP_KIT(117, listOf(VIEW_TOUCH_UP_KITS), true), - REMOVE_RECIPES(listOf(EDIT_RECIPES, REMOVE_FILE), true), - REMOVE_MATERIALS(listOf(EDIT_MATERIALS, REMOVE_FILE), true), - REMOVE_MATERIAL_TYPES(listOf(EDIT_MATERIAL_TYPES), true), - REMOVE_COMPANIES(listOf(EDIT_COMPANIES), true), - REMOVE_USERS(listOf(EDIT_USERS), true), - REMOVE_CATALOG(listOf(REMOVE_MATERIALS, REMOVE_MATERIAL_TYPES, REMOVE_COMPANIES), true), + REMOVE_RECIPES(118, listOf(EDIT_RECIPES, REMOVE_FILE), true), + REMOVE_MATERIALS(119, listOf(EDIT_MATERIALS, REMOVE_FILE), true), + REMOVE_MATERIAL_TYPES(120, listOf(EDIT_MATERIAL_TYPES), true), + REMOVE_COMPANIES(121, listOf(EDIT_COMPANIES), true), + REMOVE_USERS(122, listOf(EDIT_USERS), true), + REMOVE_CATALOG(123, listOf(REMOVE_MATERIALS, REMOVE_MATERIAL_TYPES, REMOVE_COMPANIES), true), - REMOVE_RECIPE(listOf(REMOVE_RECIPES), true), - REMOVE_MATERIAL(listOf(REMOVE_MATERIALS), true), - REMOVE_MATERIAL_TYPE(listOf(REMOVE_MATERIAL_TYPES), true), - REMOVE_COMPANY(listOf(REMOVE_COMPANIES), true), - REMOVE(listOf(REMOVE_RECIPES, REMOVE_CATALOG), true), - REMOVE_EMPLOYEE(listOf(REMOVE_USERS), true), - REMOVE_EMPLOYEE_GROUP(listOf(REMOVE_USERS), true), + REMOVE_RECIPE(124, listOf(REMOVE_RECIPES), true), + REMOVE_MATERIAL(125, listOf(REMOVE_MATERIALS), true), + REMOVE_MATERIAL_TYPE(126, listOf(REMOVE_MATERIAL_TYPES), true), + REMOVE_COMPANY(127, listOf(REMOVE_COMPANIES), true), + REMOVE(128, listOf(REMOVE_RECIPES, REMOVE_CATALOG), true), + REMOVE_EMPLOYEE(129, listOf(REMOVE_USERS), true), + REMOVE_EMPLOYEE_GROUP(130, listOf(REMOVE_USERS), true), - SET_BROWSER_DEFAULT_GROUP(listOf(VIEW_USERS), true), + SET_BROWSER_DEFAULT_GROUP(131, listOf(VIEW_USERS), true), ; operator fun contains(permission: Permission): Boolean { return permission == this || impliedPermissions.any { permission in it } } -} -fun Permission.flat(): Iterable { - return mutableSetOf(this).apply { - impliedPermissions.forEach { - addAll(it.flat()) + fun flat(): Iterable { + return mutableSetOf(this).apply { + impliedPermissions.forEach { + addAll(it.flat()) + } } } -} -/** Converts the given [Permission] to a [GrantedAuthority]. */ -fun Permission.toAuthority(): GrantedAuthority { - return SimpleGrantedAuthority(name) + /** Converts the given permission to a [GrantedAuthority]. */ + fun toAuthority(): GrantedAuthority { + return SimpleGrantedAuthority(name) + } } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/ConfigurationController.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/ConfigurationController.kt index d66b67b..c9f1e80 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/ConfigurationController.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/ConfigurationController.kt @@ -4,7 +4,6 @@ import dev.fyloz.colorrecipesexplorer.logic.config.ConfigurationLogic import dev.fyloz.colorrecipesexplorer.model.ConfigurationBase import dev.fyloz.colorrecipesexplorer.model.ConfigurationDto import dev.fyloz.colorrecipesexplorer.model.account.Permission -import dev.fyloz.colorrecipesexplorer.model.account.toAuthority import dev.fyloz.colorrecipesexplorer.restartApplication import org.springframework.http.MediaType import org.springframework.security.access.prepost.PreAuthorize diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/account/GroupTokenController.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/account/GroupTokenController.kt index b2adbd1..57d3811 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/account/GroupTokenController.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/account/GroupTokenController.kt @@ -20,8 +20,7 @@ import javax.validation.Valid @PreAuthorizeAdmin @Profile("!emergency") class GroupTokenController( - private val groupTokenLogic: GroupTokenLogic, - private val jwtLogic: JwtLogic + private val groupTokenLogic: GroupTokenLogic, private val jwtLogic: JwtLogic ) { @GetMapping fun getAll() = ok(groupTokenLogic.getAll()) @@ -29,14 +28,6 @@ class GroupTokenController( @GetMapping("{id}") fun getById(@PathVariable id: String) = ok(groupTokenLogic.getById(id)) - // TODO Remove when group tokens will be fully implemented - @Deprecated("Only use for testing purposes") - @GetMapping("{id}/cookie") - fun addCookieForId(@PathVariable id: String, response: HttpServletResponse) { - val groupToken = groupTokenLogic.getById(id) - addGroupTokenCookie(response, groupToken) - } - @PostMapping fun save(@RequestBody @Valid dto: GroupTokenSaveDto, response: HttpServletResponse) = with(groupTokenLogic.save(dto)) { @@ -44,6 +35,16 @@ class GroupTokenController( created(Constants.ControllerPaths.GROUP_TOKEN, this, this.id) } + @PutMapping("{id}/enable") + fun enable(@PathVariable id: String) = noContent { + groupTokenLogic.enable(id) + } + + @PutMapping("{id}/disable") + fun disable(@PathVariable id: String) = noContent { + groupTokenLogic.disable(id) + } + @DeleteMapping("{id}") fun deleteById(@PathVariable id: String) = noContent { groupTokenLogic.deleteById(id) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/GroupService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/GroupService.kt index 5772c5f..773deb7 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/GroupService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/GroupService.kt @@ -4,7 +4,6 @@ import dev.fyloz.colorrecipesexplorer.config.annotations.ServiceComponent import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto import dev.fyloz.colorrecipesexplorer.model.account.Group import dev.fyloz.colorrecipesexplorer.model.account.Permission -import dev.fyloz.colorrecipesexplorer.model.account.flat import dev.fyloz.colorrecipesexplorer.repository.GroupRepository import dev.fyloz.colorrecipesexplorer.service.BaseService import dev.fyloz.colorrecipesexplorer.service.Service diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/GroupTokenService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/GroupTokenService.kt index 6cfdc3a..3cfb7c9 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/GroupTokenService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/GroupTokenService.kt @@ -44,5 +44,5 @@ class DefaultGroupTokenService(private val repository: GroupTokenRepository, pri GroupTokenDto(entity.id, entity.name, entity.isValid, groupService.toDto(entity.group)) override fun toEntity(dto: GroupTokenDto) = - GroupToken(dto.id, dto.name, dto.isValid, groupService.toEntity(dto.group)) + GroupToken(dto.id, dto.name, dto.enabled, groupService.toEntity(dto.group)) } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/UserService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/UserService.kt index 31c5a23..08a6c26 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/UserService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/account/UserService.kt @@ -5,7 +5,6 @@ import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto import dev.fyloz.colorrecipesexplorer.model.account.Permission import dev.fyloz.colorrecipesexplorer.model.account.User -import dev.fyloz.colorrecipesexplorer.model.account.flat import dev.fyloz.colorrecipesexplorer.repository.UserRepository import dev.fyloz.colorrecipesexplorer.service.BaseService import dev.fyloz.colorrecipesexplorer.service.Service diff --git a/src/main/resources/application-debug.properties b/src/main/resources/application-debug.properties index 72fc330..6555358 100644 --- a/src/main/resources/application-debug.properties +++ b/src/main/resources/application-debug.properties @@ -1 +1 @@ -spring.jpa.show-sql=true \ No newline at end of file +spring.jpa.show-sql=false