Commit b4c3b10d authored by Ghitha Dinan's avatar Ghitha Dinan

token interceptor fixing

parent 863081af
...@@ -90,6 +90,13 @@ ...@@ -90,6 +90,13 @@
<artifactId>spring-boot-starter-mail</artifactId> <artifactId>spring-boot-starter-mail</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.10.00</version>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
package id.co.sangkuriang.inovasi.daerah.master.config package id.co.sangkuriang.inovasi.daerah.master.config
import id.co.sangkuriang.inovasi.daerah.master.constant.USER_ADMIN_ALLOWED_PATH import id.co.sangkuriang.inovasi.daerah.master.constant.AUDIENCE_FILTER_PATH
import id.co.sangkuriang.inovasi.daerah.master.interceptor.TokenInterceptor import id.co.sangkuriang.inovasi.daerah.master.interceptor.TokenInterceptor
import org.springframework.boot.web.servlet.FilterRegistrationBean import org.springframework.boot.web.servlet.FilterRegistrationBean
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
...@@ -24,9 +24,13 @@ class SpringWebConfig : WebMvcConfigurer { ...@@ -24,9 +24,13 @@ class SpringWebConfig : WebMvcConfigurer {
fun tokenFilter(): FilterRegistrationBean<TokenInterceptor>? { fun tokenFilter(): FilterRegistrationBean<TokenInterceptor>? {
val registrationBean: FilterRegistrationBean<TokenInterceptor> = val registrationBean: FilterRegistrationBean<TokenInterceptor> =
FilterRegistrationBean<TokenInterceptor>() FilterRegistrationBean<TokenInterceptor>()
USER_ADMIN_ALLOWED_PATH.forEach {
registrationBean.addUrlPatterns("/$it/*") AUDIENCE_FILTER_PATH.forEach {
it.value.forEach {
registrationBean.addUrlPatterns(it)
}
} }
registrationBean.filter = TokenInterceptor() registrationBean.filter = TokenInterceptor()
registrationBean.order = 1 registrationBean.order = 1
return registrationBean return registrationBean
......
package id.co.sangkuriang.inovasi.daerah.master.constant package id.co.sangkuriang.inovasi.daerah.master.constant
const val SECRET = "INOVASI-DAERAH"
const val TOKEN_PREFIX = "Bearer " const val TOKEN_PREFIX = "Bearer "
const val HEADER_STRING = "Authorization" const val HEADER_STRING = "Authorization"
const val AUTH_URL = "https://auth.inovasi-daerah.spbe.sangkuriang.co.id/auth" const val AUTH_URL = "https://auth.inovasi-daerah.spbe.sangkuriang.co.id/auth"
......
...@@ -9,3 +9,5 @@ const val VALIDATOR_MSG_HAS_USED = "sudah di pakai" ...@@ -9,3 +9,5 @@ const val VALIDATOR_MSG_HAS_USED = "sudah di pakai"
const val VALIDATOR_MSG_NOT_FOUND = "tidak di temukan" const val VALIDATOR_MSG_NOT_FOUND = "tidak di temukan"
const val VALIDATOR_MSG_DUPLICATE = "Data sudah ada di database" const val VALIDATOR_MSG_DUPLICATE = "Data sudah ada di database"
const val VALIDATOR_MSG_NOT_HAVE_ACCESS = "tidak mempunyai hak akses"
package id.co.sangkuriang.inovasi.daerah.master.helpers
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import id.co.sangkuriang.inovasi.daerah.master.constant.HEADER_STRING
import id.co.sangkuriang.inovasi.daerah.master.model.response.ReturnData
import kong.unirest.Unirest
import org.apache.http.client.HttpClient
import org.apache.http.conn.ssl.NoopHostnameVerifier
import org.apache.http.conn.ssl.TrustSelfSignedStrategy
import org.apache.http.impl.client.HttpClients
import org.apache.http.ssl.SSLContextBuilder
import java.security.cert.X509Certificate
import javax.net.ssl.SSLContext
class RequestHelpers {
companion object {
private fun configHttpClient() {
val sslContext: SSLContext = SSLContextBuilder().loadTrustMaterial(
null,
object : TrustSelfSignedStrategy() {
override fun isTrusted(chain: Array<X509Certificate?>?, authType: String?): Boolean {
return true
}
}
).build()
val customHttpClient: HttpClient = HttpClients.custom().setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier()).build()
Unirest.config().httpClient(customHttpClient)
}
fun authDetail(authUrl: String, bearer: String): ReturnData? {
return try {
configHttpClient()
val objectMapper = ObjectMapper()
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
val reqUrl = "$authUrl/detail"
val response = Unirest.get(reqUrl)
.header("Content-Type", "application/json")
.header(HEADER_STRING, bearer)
.asString()
objectMapper.readValue(response.body, ReturnData::class.java)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
}
}
package id.co.sangkuriang.inovasi.daerah.master.interceptor package id.co.sangkuriang.inovasi.daerah.master.interceptor
import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import com.auth0.jwt.exceptions.JWTCreationException import com.auth0.jwt.exceptions.JWTCreationException
import com.auth0.jwt.exceptions.JWTDecodeException import com.auth0.jwt.exceptions.JWTDecodeException
import com.auth0.jwt.exceptions.JWTVerificationException import com.auth0.jwt.exceptions.JWTVerificationException
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import id.co.sangkuriang.inovasi.daerah.master.constant.HEADER_STRING import id.co.sangkuriang.inovasi.daerah.master.constant.*
import id.co.sangkuriang.inovasi.daerah.master.constant.SECRET import id.co.sangkuriang.inovasi.daerah.master.helpers.RequestHelpers
import id.co.sangkuriang.inovasi.daerah.master.constant.TOKEN_PREFIX
import id.co.sangkuriang.inovasi.daerah.master.constant.VALIDATOR_MSG_NOT_FOUND
import id.co.sangkuriang.inovasi.daerah.master.model.response.ReturnData import id.co.sangkuriang.inovasi.daerah.master.model.response.ReturnData
import id.co.sangkuriang.inovasi.daerah.master.pojo.Users
import id.co.sangkuriang.inovasi.daerah.master.utility.getFullUrl
import id.co.sangkuriang.inovasi.daerah.master.utility.getPathUrl import id.co.sangkuriang.inovasi.daerah.master.utility.getPathUrl
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.util.ContentCachingRequestWrapper import org.springframework.web.util.ContentCachingRequestWrapper
import javax.servlet.Filter import javax.servlet.Filter
...@@ -35,19 +33,15 @@ class TokenInterceptor : Filter { ...@@ -35,19 +33,15 @@ class TokenInterceptor : Filter {
// If header doesn't contain Bearer or is null will return nothing and exit // If header doesn't contain Bearer or is null will return nothing and exit
if (header == null || !header.startsWith(TOKEN_PREFIX)) { if (header == null || !header.startsWith(TOKEN_PREFIX)) {
responseException(res, "Sorry, your provided token information not exists") responseException(res, "Token $VALIDATOR_MSG_REQUIRED")
return return
} }
var authentication: UsernamePasswordAuthenticationToken? = null var authentication: UsernamePasswordAuthenticationToken? = null
var successAuth = true var successAuth = true
try { try {
authentication = getAuthentication(req) authentication = getAuthentication(req)
if (authentication == null) {
responseException(res, "User $VALIDATOR_MSG_NOT_FOUND")
}
} catch (e: JWTDecodeException) { } catch (e: JWTDecodeException) {
successAuth = false successAuth = false
responseException(res, e.message.toString()) responseException(res, e.message.toString())
...@@ -60,6 +54,9 @@ class TokenInterceptor : Filter { ...@@ -60,6 +54,9 @@ class TokenInterceptor : Filter {
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
successAuth = false successAuth = false
responseException(res, e.message.toString()) responseException(res, e.message.toString())
} catch (e: Exception) {
successAuth = false
responseException(res, e.message.toString())
} }
SecurityContextHolder.getContext().authentication = authentication SecurityContextHolder.getContext().authentication = authentication
...@@ -88,34 +85,56 @@ class TokenInterceptor : Filter { ...@@ -88,34 +85,56 @@ class TokenInterceptor : Filter {
JWTVerificationException::class, JWTVerificationException::class,
IllegalArgumentException::class IllegalArgumentException::class
) )
private fun getAuthentication(request: HttpServletRequest): UsernamePasswordAuthenticationToken? { private fun getAuthentication(request: HttpServletRequest): UsernamePasswordAuthenticationToken? {
try {
val token = request.getHeader(HEADER_STRING) val token = request.getHeader(HEADER_STRING)
if (token != null) { val reqAuthDetail: ReturnData =
// parse jwt token from request and validate it internal authentication RequestHelpers.authDetail(AUTH_URL, token) ?: throw Exception("User $VALIDATOR_MSG_NOT_FOUND")
val jwt =
JWT.require(Algorithm.HMAC512(SECRET.toByteArray())).build().verify(token.replace(TOKEN_PREFIX, "")) reqAuthDetail.success?.let {
return if (jwt.subject != null) { // return principal username if (!it) {
val pathUrl = getPathUrl(request) throw Exception(reqAuthDetail.message)
val audience = jwt.audience?.get(0) }
}
println("pathUrl => $audience - ${request.method} - $pathUrl")
val objectMapper = ObjectMapper()
if (audience == "user") { objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
val tokenParse = token + System.currentTimeMillis() val users: Users =
JWT.require(Algorithm.HMAC512(SECRET.toByteArray())).build() objectMapper.readValue(objectMapper.writeValueAsString(reqAuthDetail.data), Users::class.java)
.verify(tokenParse.replace(TOKEN_PREFIX, ""))
var audience = "user-admin"
if (users.roleId == ROLE_USER_ID) {
audience = "user"
}
var isAllowed = false
AUDIENCE_FILTER_PATH[audience]?.forEach lambda@{
if (it.contains("/*")) {
if (getPathUrl(request).contains(it.replaceFirst("/", "").replace("/*", ""))) {
isAllowed = true
return@lambda
}
} else {
if (getFullUrl(request).contains(it)) {
isAllowed = true
return@lambda
}
}
} }
return if (isAllowed) {
UsernamePasswordAuthenticationToken( UsernamePasswordAuthenticationToken(
jwt.subject, ObjectMapper().writeValueAsString(users),
audience, audience,
ArrayList<GrantedAuthority>() arrayListOf()
) )
} else { } else {
null throw Exception("User $VALIDATOR_MSG_NOT_HAVE_ACCESS")
} }
} catch (e: Exception) {
e.printStackTrace()
throw e
} }
return null
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment