authenticaction, registration, login

This commit is contained in:
Bossanyi Tibor
2020-06-10 16:19:48 +02:00
parent dba2228939
commit c685dfb71c
25 changed files with 608 additions and 38 deletions
@@ -0,0 +1,31 @@
package com.aitrainer.api.security
import com.aitrainer.api.ApiApplication
import com.aitrainer.api.controller.ApplicationProperties
import com.aitrainer.api.controller.Singleton
import com.aitrainer.api.repository.ConfigurationRepository
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
@Suppress("unused")
@Aspect
@Component
class AuthenticationControllerAspect {
private val logger = LoggerFactory.getLogger(ApiApplication::class.simpleName)
@Autowired
private lateinit var configurationRepository: ConfigurationRepository
@Autowired
private lateinit var properties: ApplicationProperties
@Before("execution(* com.aitrainer.api.security.JwtAuthenticationController.*(..))")
fun customerControllerAspect(joinPoint: JoinPoint) {
println("auth controller join")
Singleton.checkDBUpdate(configurationRepository, properties)
}
}
@@ -0,0 +1,49 @@
package com.aitrainer.api.security
import com.aitrainer.api.service.UserDetailsServiceImpl
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.authentication.DisabledException
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.web.bind.annotation.*
import org.springframework.stereotype.Component
@Component
@RestController
//@CrossOrigin
@RequestMapping("/api")
class JwtAuthenticationController {
@Autowired
private val authenticationManager: AuthenticationManager? = null
@Autowired
private val jwtTokenUtil: JwtTokenUtil? = null
@Autowired
private val jwtUserDetailsService: UserDetailsServiceImpl? = null
@PostMapping("/authenticate")
fun generateAuthenticationToken(@RequestBody authenticationRequest: JwtRequest): ResponseEntity<*> {
authenticate(authenticationRequest.username!!, authenticationRequest.password!!)
val userDetails = jwtUserDetailsService
?.loadUserByUsername(authenticationRequest.username)
val token: String = jwtTokenUtil!!.generateToken(userDetails!!)
return ResponseEntity.ok<Any>(JwtResponse(token))
}
private fun authenticate(username: String, password: String) {
try {
authenticationManager!!.authenticate(UsernamePasswordAuthenticationToken(username, password))
} catch (e: DisabledException) {
throw Exception("USER_DISABLED", e)
} catch (e: BadCredentialsException) {
throw Exception("INVALID_CREDENTIALS", e)
}
}
}
@@ -0,0 +1,23 @@
package com.aitrainer.api.security
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.stereotype.Component
import java.io.IOException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import java.io.Serializable
import org.springframework.security.core.AuthenticationException
@Component
class JwtAuthenticationEntryPoint : AuthenticationEntryPoint, Serializable {
@Throws(IOException::class)
override fun commence(request: HttpServletRequest?, response: HttpServletResponse,
authException: AuthenticationException?) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized")
}
companion object {
private const val serialVersionUID = -7858869558953243875L
}
}
@@ -0,0 +1,19 @@
package com.aitrainer.api.security
import java.io.Serializable
class JwtRequest : Serializable {
var username: String? = null
var password: String? = null
//default constructor for JSON Parsing
constructor(username: String?, password: String?) {
this.username = username
this.password = password
}
companion object {
private const val serialVersionUID = 5926468583005150707L
}
}
@@ -0,0 +1,77 @@
package com.aitrainer.api.security
import com.aitrainer.api.service.UserDetailsServiceImpl
import io.jsonwebtoken.ExpiredJwtException
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
import java.io.IOException
import javax.servlet.FilterChain
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
@Component
class JwtRequestFilter : OncePerRequestFilter() {
@Autowired
private val jwtUserDetailsService: UserDetailsServiceImpl? = null
@Autowired
private val jwtTokenUtil: JwtTokenUtil? = null
//@Autowired
//private lateinit var authenticationController: JwtAuthenticationController
@Throws(ServletException::class, IOException::class)
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
val requestTokenHeader = request.getHeader("Authorization")
var username: String? = null
var jwtToken: String? = null
// JWT Token is in the form "Bearer token". Remove Bearer word and get only the Token
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer")) {
jwtToken = requestTokenHeader.substring(7)
try {
username = jwtTokenUtil!!.getUsernameFromToken(jwtToken)
} catch (e: IllegalArgumentException) {
println("Unable to get JWT Token")
} catch (e: ExpiredJwtException) {
println("JWT Token has expired")
}
} else if (requestTokenHeader != null && requestTokenHeader.equals("1") ) {
logger.warn("Authenticate")
//val credentials: User = ObjectMapper().readValue(request.inputStream, User::class.java)
} else {
logger.warn("JWT Token does not begin with Bearer String")
}
//Once we get the token validate it.
if (username != null && SecurityContextHolder.getContext().authentication == null) {
val userDetails: UserDetails = jwtUserDetailsService!!.loadUserByUsername(username)
// if token is valid configure Spring Security to manually set authentication
if (jwtTokenUtil!!.validateToken(jwtToken!!, userDetails)) {
val usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.authorities)
usernamePasswordAuthenticationToken.details = WebAuthenticationDetailsSource().buildDetails(request)
// After setting the Authentication in the context, we specify
// that the current user is authenticated. So it passes the Spring Security Configurations successfully.
SecurityContextHolder.getContext().authentication = usernamePasswordAuthenticationToken
}
}
chain.doFilter(request, response)
}
/*private fun readUserCredentials(request: HttpServletRequest): UserCredentials? {
return try {
ObjectMapper().readValue(request.inputStream, UserCredentials::class.java)
} catch (ioe: IOException) {
throw BadCredentialsException("Invalid request", ioe)
}
}*/
}
@@ -0,0 +1,12 @@
package com.aitrainer.api.security
import java.io.Serializable
class JwtResponse(val token: String) : Serializable {
companion object {
private const val serialVersionUID = -8091879091924046844L
}
}
@@ -0,0 +1,65 @@
package com.aitrainer.api.security
import com.aitrainer.api.service.ServiceBeans
import com.aitrainer.api.service.UserDetailsServiceImpl
import org.springframework.beans.factory.annotation.Autowired
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.config.http.SessionCreationPolicy
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
@Configuration
@EnableWebSecurity
class JwtSecurityConfig : WebSecurityConfigurerAdapter() {
@Autowired
private val jwtAuthenticationEntryPoint: JwtAuthenticationEntryPoint? = null
@Autowired
private val jwtUserDetailsService: UserDetailsServiceImpl? = null
@Autowired
private val jwtRequestFilter: JwtRequestFilter? = null
@Autowired
private val serviceBeans: ServiceBeans? = null
override fun configure(auth: AuthenticationManagerBuilder?) {
auth!!.userDetailsService(jwtUserDetailsService).passwordEncoder(serviceBeans!!.passwordEncoder())
}
@Bean
@Throws(Exception::class)
override fun authenticationManagerBean(): AuthenticationManager {
return super.authenticationManagerBean()
}
@Throws(Exception::class)
override fun configure(httpSecurity: HttpSecurity) {
// We don't need CSRF for this example
httpSecurity.
csrf().disable().
// dont authenticate this particular request
authorizeRequests().antMatchers("/api/authenticate").permitAll().
// all other requests need to be authenticated
anyRequest().authenticated().and().
// make sure we use stateless session; session won't be used to
// store user's state.
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().
// Add a filter to validate the tokens with every request
//addFilterAt(JwtAuthenticationFilter(authenticationManagerBean()), UsernamePasswordAuthenticationFilter::class.java).
addFilterAfter(jwtRequestFilter, UsernamePasswordAuthenticationFilter::class.java).
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}
}
@@ -0,0 +1,67 @@
package com.aitrainer.api.security
import org.springframework.beans.factory.annotation.Value
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Component
import java.util.*
import java.io.Serializable
import io.jsonwebtoken.Claims
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
@Component
class JwtTokenUtil : Serializable {
@Value("\${jwt.secret}")
private val secret: String? = null
fun getUsernameFromToken(token: String?): String {
return getClaimFromToken(token, Claims::getSubject)
}
fun getIssuedAtDateFromToken(token: String?): Date {
return getClaimFromToken<Date>(token, Claims::getIssuedAt)
}
fun getExpirationDateFromToken(token: String?): Date {
return getClaimFromToken<Date>(token, Claims::getExpiration)
}
fun <T> getClaimFromToken( token: String?, claimsResolver: ( Claims.()-> T ) ): T {
val claims: Claims = getAllClaimsFromToken(token)
return claims.claimsResolver()
}
private fun getAllClaimsFromToken(token: String?): Claims {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).body
}
private fun isTokenExpired(token: String): Boolean {
val expiration: Date = getExpirationDateFromToken(token)
return expiration.before(Date())
}
fun generateToken(userDetails: UserDetails): String {
val claims: Map<String, Any> = HashMap()
return doGenerateToken(claims, userDetails.username)
}
private fun doGenerateToken(claims: Map<String, Any>, subject: String): String {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(Date(System.currentTimeMillis()))
.setExpiration(Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000)).signWith(SignatureAlgorithm.HS512, secret).compact()
}
fun canTokenBeRefreshed(token: String): Boolean {
return !isTokenExpired(token)
}
fun validateToken(token: String, userDetails: UserDetails): Boolean {
val username = getUsernameFromToken(token)
return username == userDetails.username && !isTokenExpired(token)
}
companion object {
private const val serialVersionUID = -2550185165626007488L
const val JWT_TOKEN_VALIDITY = 5 * 60 * 60.toLong()
}
}