Skip to content

Commit

Permalink
Add auth service methods for validating jwt roles
Browse files Browse the repository at this point in the history
  • Loading branch information
bdmendes committed May 3, 2023
1 parent 9463233 commit a949fd7
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import com.nimbusds.jose.jwk.source.ImmutableJWKSet
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
Expand All @@ -23,6 +25,8 @@ import org.springframework.web.filter.CorsFilter
import org.springframework.web.servlet.HandlerExceptionResolver

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
class AuthConfig(
val authConfigProperties: AuthConfigProperties,
@Qualifier("handlerExceptionResolver") val exceptionResolver: HandlerExceptionResolver
Expand Down Expand Up @@ -71,7 +75,7 @@ class AuthConfig(

fun rolesConverter(): JwtAuthenticationConverter? {
val authoritiesConverter = JwtGrantedAuthoritiesConverter()
authoritiesConverter.setAuthorityPrefix("ROLE_")
authoritiesConverter.setAuthorityPrefix("")
val converter = JwtAuthenticationConverter()
converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter)
return converter
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package pt.up.fe.ni.website.backend.controller

import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import pt.up.fe.ni.website.backend.dto.auth.LoginDto
import pt.up.fe.ni.website.backend.dto.auth.TokenDto
import pt.up.fe.ni.website.backend.model.Account
import pt.up.fe.ni.website.backend.model.Project
import pt.up.fe.ni.website.backend.repository.ActivityRepository
import pt.up.fe.ni.website.backend.service.AuthService

@RestController
@RequestMapping("/auth")
class AuthController(val authService: AuthService) {
class AuthController(val authService: AuthService, val repository: ActivityRepository<Project>) {
@PostMapping("/new")
fun getNewToken(@RequestBody loginDto: LoginDto): Map<String, String> {
val account = authService.authenticate(loginDto.email, loginDto.password)
Expand All @@ -28,10 +30,14 @@ class AuthController(val authService: AuthService) {
return mapOf("access_token" to accessToken)
}

@PreAuthorize("isAuthenticated()")
@GetMapping
@PreAuthorize("@authService.hasPermission(1)")
fun checkAuthentication(): Map<String, Account> {
fun checkAuthentication(): Map<String, Any> {
val authentication = SecurityContextHolder.getContext().authentication
val account = authService.getAuthenticatedAccount()
return mapOf("authenticated_user" to account)
return mapOf(
"authenticated_user" to account,
"jwt_permissions" to authentication.authorities.map { it.toString() }.toList()
)
}
}
39 changes: 19 additions & 20 deletions src/main/kotlin/pt/up/fe/ni/website/backend/service/AuthService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pt.up.fe.ni.website.backend.service

import java.time.Duration
import java.time.Instant
import java.util.Locale
import java.util.stream.Collectors
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.GrantedAuthority
Expand All @@ -13,31 +14,40 @@ import org.springframework.security.oauth2.jwt.JwtDecoder
import org.springframework.security.oauth2.jwt.JwtEncoder
import org.springframework.security.oauth2.jwt.JwtEncoderParameters
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException
import org.springframework.stereotype.Component
import org.springframework.stereotype.Service
import pt.up.fe.ni.website.backend.config.auth.AuthConfigProperties
import pt.up.fe.ni.website.backend.model.Account
import pt.up.fe.ni.website.backend.model.Project
import pt.up.fe.ni.website.backend.model.permissions.Permission
import pt.up.fe.ni.website.backend.repository.ActivityRepository
import pt.up.fe.ni.website.backend.service.activity.ActivityService

@Service
@Component("authService")
class AuthService(
val accountService: AccountService,
val activityService: ActivityService,
val authConfigProperties: AuthConfigProperties,
val jwtEncoder: JwtEncoder,
val jwtDecoder: JwtDecoder,
private val passwordEncoder: PasswordEncoder,
val repository: ActivityRepository<Project>
) {
fun hasPermission(permission: Permission): Boolean {
println("here")
val authorities = SecurityContextHolder.getContext().authentication.authorities
for (a in authorities) {
println(a)
fun hasPermission(permission: String): Boolean {
val authentication = SecurityContextHolder.getContext().authentication
return authentication.authorities.any {
it.toString() == permission
}
}

fun hasActivityPermission(activityId: Long, permission: String): Boolean {
val authentication = SecurityContextHolder.getContext().authentication

val activity = activityService.getActivityById(activityId)
val name = activity.title.filter { it.isLetterOrDigit() }.uppercase(Locale.getDefault())

return authentication.authorities.any { it ->
val payload = it.toString().split(":")
payload.size == 2 && payload[0] == name && payload[1].split("-").any { p -> p == permission }
}
return false
}

fun authenticate(email: String, password: String): Account {
Expand Down Expand Up @@ -87,17 +97,6 @@ class AuthService(
}

private fun generateAuthorities(account: Account): List<GrantedAuthority> {
/*val testRole = Role("MEMBER", Permissions(listOf(Permission.CREATE_ACCOUNT, Permission.CREATE_ACTIVITY)), false)
val testPerActivityRole = PerActivityRole(
Permissions(listOf(Permission.CREATE_ACCOUNT, Permission.CREATE_ACTIVITY))
)
val activity = Project("Test Activity", "Test Description", mutableListOf(), mutableListOf())
testPerActivityRole.activity = activity
repository.save(activity)
testRole.associatedActivities.add(testPerActivityRole)
account.roles.add(testRole)
*/

return account.roles.map {
it.toString().split(" ")
}.flatten().distinct().map {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ abstract class AbstractActivityService<T : Activity>(
protected val repository: ActivityRepository<T>,
protected val accountService: AccountService
) {
fun getAll() = repository.findAll().toList()

fun getActivityById(id: Long): T = repository.findByIdOrNull(id)
?: throw NoSuchElementException(ErrorMessages.activityNotFound(id))

Expand Down

0 comments on commit a949fd7

Please sign in to comment.