#30 Disallow log in and authorization from disabled or removed group tokens
continuous-integration/drone/push Build is passing Details

This commit is contained in:
william 2022-04-29 17:20:17 -04:00
parent 531fa252d2
commit ff8ba46ce2
16 changed files with 194 additions and 116 deletions

View File

@ -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 {

View File

@ -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
}
}
}

View File

@ -101,7 +101,7 @@ abstract class BaseSecurityConfig(
BasicAuthenticationFilter::class.java
)
.addFilter(
JwtAuthorizationFilter(jwtLogic, authenticationManager())
JwtAuthorizationFilter(jwtLogic, groupTokenLogic, authManager)
)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()

View File

@ -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
}
}

View File

@ -8,7 +8,7 @@ data class GroupTokenDto(
val name: String,
val isValid: Boolean,
val enabled: Boolean,
val group: GroupDto
)

View File

@ -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<GrantedAuthority>, val isGroup: Boolean)
class UserDetails(
val id: String,
private val username: String,
private val password: String,
val group: GroupDto?,
val permissions: Collection<Permission>
val permissions: Collection<Permission>,
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<Permission>
)
)

View File

@ -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<GroupTokenDto>
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<String>()
@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)) {

View File

@ -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<Map<String, *>>(objectMapper))
.signWith(secretKey)
private val jwtBuilder
get() =
Jwts.builder()
.serializeToJsonWith(JacksonSerializer<Map<String, *>>(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<Collection<Permission>>(serializedPermissions)
val permissionsIds = objectMapper.readValue<Collection<Int>>(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<GrantedAuthority>)

View File

@ -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")) {

View File

@ -4,32 +4,34 @@ import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.authority.SimpleGrantedAuthority
enum class Permission(
val impliedPermissions: List<Permission> = listOf(),
val id: Int,
private val impliedPermissions: List<Permission> = 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<Permission> {
return mutableSetOf(this).apply {
impliedPermissions.forEach {
addAll(it.flat())
fun flat(): Iterable<Permission> {
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)
}
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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))
}

View File

@ -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

View File

@ -1 +1 @@
spring.jpa.show-sql=true
spring.jpa.show-sql=false