Commit 65c9aade authored by Ghitha Dinan's avatar Ghitha Dinan

Initial commit

parents
Pipeline #398 canceled with stages
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
/*
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if (mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if (mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if (!outputFile.getParentFile().exists()) {
if (!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
This diff is collapsed.
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>id.go.kemenag.madrasah</groupId>
<artifactId>pmrms-auth</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>pmrms-auth</name>
<description>PMRMS Auth Service</description>
<properties>
<java.version>1.8</java.version>
<kotlin.version>1.5.30</kotlin.version>
<start-class>id.go.kemenag.madrasah.pmrms.auth.PmrmsAuthApplicationKt</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-validator/commons-validator -->
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.7</version>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!-- send email -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- unirest -->
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.13.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- RabbitMQ Starter Dependency (Not required if you're using the simple in-memory broker for STOMP) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- Following dependency is required for Full Featured STOMP Broker Relay -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-reactor-netty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.3</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/kotlin</sourceDirectory>
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<mainClass>${start-class}</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
<jvmTarget>1.8</jvmTarget>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</build>
</project>
package id.go.kemenag.madrasah.pmrms.auth
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class PmrmsAuthApplication
fun main(args: Array<String>) {
runApplication<PmrmsAuthApplication>(*args)
}
package id.go.kemenag.madrasah.pmrms.auth.config
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
@Configuration
class SecurityConfig : WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http.httpBasic()?.disable()
http.cors()?.and()?.csrf()?.disable()
}
}
package id.go.kemenag.madrasah.pmrms.auth.config
import id.go.kemenag.madrasah.pmrms.auth.constant.AUDIENCE_FILTER_PATH
import id.go.kemenag.madrasah.pmrms.auth.interceptor.TokenInterceptor
import org.springframework.boot.web.servlet.FilterRegistrationBean
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.servlet.config.annotation.CorsRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@Configuration
class SpringWebConfig : WebMvcConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("/**")
.allowedMethods("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "PUT", "TRACE")
.allowedOrigins("*")
.allowedHeaders("*")
.maxAge(60000)
}
@Bean
fun tokenFilter(): FilterRegistrationBean<TokenInterceptor>? {
val registrationBean: FilterRegistrationBean<TokenInterceptor> =
FilterRegistrationBean<TokenInterceptor>()
AUDIENCE_FILTER_PATH.forEach {
it.value.forEach {
registrationBean.addUrlPatterns(it)
}
}
registrationBean.filter = TokenInterceptor()
registrationBean.order = 1
return registrationBean
}
}
package id.go.kemenag.madrasah.pmrms.auth.constant
const val EXPIRATION_TIME: Long = 864000000 // 10 days (1 hour = 3600000)
const val SECRET = "INOVASI-DAERAH"
const val TOKEN_PREFIX = "Bearer "
const val HEADER_STRING = "Authorization"
val USER_ADMIN_ALLOWED_PATH =
listOf(
"/users/*",
"/auth/logout",
"/auth/detail",
"/profile/*",
)
val AUDIENCE_FILTER_PATH = mapOf(
"admin" to USER_ADMIN_ALLOWED_PATH
)
package id.go.kemenag.madrasah.pmrms.auth.constant
const val VALIDATOR_MSG_REQUIRED = "harus di isi"
const val VALIDATOR_MSG_NOT_VALID = "tidak valid"
const val VALIDATOR_MSG_HAS_USED = "sudah di pakai"
const val VALIDATOR_MSG_NOT_FOUND = "tidak di temukan"
const val VALIDATOR_MSG_NOT_HAVE_ACCESS = "tidak mempunyai hak akses"
const val VALIDATOR_MSG_DELETE_RELATION = "Data tidak dapat di hapus."
const val VALIDATOR_MSG_REQUEST_FAILED = "Gagal melakukan request data"
package id.go.kemenag.madrasah.pmrms.auth.contoller
import id.go.kemenag.madrasah.pmrms.auth.model.request.auth.LoginRequest
import id.go.kemenag.madrasah.pmrms.auth.model.response.ReturnData
import id.go.kemenag.madrasah.pmrms.auth.service.AuthService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
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 javax.validation.Valid
@RestController
@RequestMapping(path = ["auth"])
class AuthController {
@Autowired
private lateinit var service: AuthService
@PostMapping(value = ["login"], produces = ["application/json"])
fun login(@Valid @RequestBody request: LoginRequest): ResponseEntity<ReturnData> {
return service.login(request)
}
}
package id.go.kemenag.madrasah.pmrms.auth.contoller
import id.go.kemenag.madrasah.pmrms.auth.exception.BaseException
import id.go.kemenag.madrasah.pmrms.auth.model.response.ErrorMessage
import id.go.kemenag.madrasah.pmrms.auth.model.response.ReturnData
import org.springframework.core.Ordered
import org.springframework.core.annotation.Order
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.validation.BindException
import org.springframework.validation.BindingResult
import org.springframework.validation.ObjectError
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.context.request.WebRequest
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
import java.util.function.Consumer
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
class CustomExceptionHandler : ResponseEntityExceptionHandler() {
override fun handleMethodArgumentNotValid(
ex: MethodArgumentNotValidException,
headers: HttpHeaders,
status: HttpStatus,
request: WebRequest
): ResponseEntity<Any> {
val errors = mutableListOf<ErrorMessage>()
ex.bindingResult.fieldErrors.forEach { fieldError ->
errors.add(ErrorMessage(fieldError.field, fieldError.defaultMessage.toString()))
}
generateObjectErrors(ex.bindingResult)?.let {
errors.add(ErrorMessage(it.keys.toString(), it.values.toString()))
}
ex.printStackTrace()
return ResponseEntity<Any>(
ReturnData(
data = errors,
message = status.name
),
status
)
}
private fun generateObjectErrors(result: BindingResult): Map<String, String>? {
val fieldErrorMap: MutableMap<String, String> = HashMap()
result.globalErrors.forEach(Consumer { objectError: ObjectError ->
fieldErrorMap["confirmPassword"] = objectError.defaultMessage ?: ""
})
if (fieldErrorMap.isNotEmpty()) {
return fieldErrorMap
}
return null
}
override fun handleBindException(
ex: BindException,
headers: HttpHeaders,
status: HttpStatus,
request: WebRequest
): ResponseEntity<Any> {
val errors = mutableListOf<ErrorMessage>()
ex.bindingResult.fieldErrors.forEach { fieldError ->
errors.add(ErrorMessage(fieldError.field, fieldError.defaultMessage.toString()))
}
generateObjectErrors(ex.bindingResult)?.let {
errors.add(ErrorMessage(it.keys.toString(), it.values.toString()))
}
ex.printStackTrace()
return ResponseEntity<Any>(
ReturnData(
data = errors,
message = status.name
),
status
)
}
@ExceptionHandler(RuntimeException::class)
fun handleRuntimeException(ex: Exception, request: WebRequest?): ResponseEntity<Any?>? {
ex.printStackTrace()
val response = ReturnData()
response.success = false
response.message = "Terjadi kesalahan sistem. Silahkan ulangi beberapa saat lagi"
var status = HttpStatus.INTERNAL_SERVER_ERROR
if (ex is BaseException) {
ex.printStackTrace()
if (ex.status != status) {
response.message = ex.message
ex.data?.let {
response.data = it
}
status = ex.status
}
} else {
return ResponseEntity(response, status)
}
return ResponseEntity(response, status)
}
}
package id.go.kemenag.madrasah.pmrms.auth.exception
import org.springframework.http.HttpStatus
/**
*
* response status code indicates that the server cannot or will not process
* the request due to something that is perceived to be a client error
* (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
*/
class BadRequestException : BaseException {
constructor(message: String? = "Bad Request") {
this.code = "400"
this.message = message!!
this.status = HttpStatus.BAD_REQUEST
}
constructor(message: String? = "Bad Request", data: Any?) {
this.code = "400"
this.message = message!!
this.status = HttpStatus.BAD_REQUEST
this.data = data
}
}
package id.go.kemenag.madrasah.pmrms.auth.exception
import org.springframework.http.HttpStatus
open class BaseException : RuntimeException() {
var code = "500"
override var message = ""
var status = HttpStatus.INTERNAL_SERVER_ERROR
var data: Any? = null
}
package id.go.kemenag.madrasah.pmrms.auth.exception
import org.springframework.http.HttpStatus
/**
* The 409 (Conflict) status code indicates that the request could not
* be completed due to a conflict with the current state of the target
* resource. This code is used in situations where the user might be
* able to resolve the conflict and resubmit the request. The server
* SHOULD generate a payload that includes enough information for a user
* to recognize the source of the conflict.
*/
class ConflictException : BaseException {
constructor() {
this.code = "409"
this.message = "Conflict"
this.status = HttpStatus.CONFLICT
}
constructor(message: String?) {
this.code = "409"
this.message = message!!
this.status = HttpStatus.CONFLICT
}
}
package id.go.kemenag.madrasah.pmrms.auth.exception
import org.springframework.http.HttpStatus
/**
* The 500 (Internal Server Error) status code indicates that the server
* encountered an unexpected condition that prevented it from fulfilling
* the request.
*/
class InternalServerErrorException : BaseException {
constructor() {
this.code = "500"
this.message = "Internal Server Error"
this.status = HttpStatus.INTERNAL_SERVER_ERROR
}
constructor(message: String?) {
this.code = "500"
this.message = message!!
this.status = HttpStatus.INTERNAL_SERVER_ERROR
}
}
package id.go.kemenag.madrasah.pmrms.auth.exception
import org.springframework.http.HttpStatus
/**
* The 404 (Not Found) status code indicates that the origin server did
* not find a current representation for the target resource or is not
* willing to disclose that one exists. A 404 status code does not
* indicate whether this lack of representation is temporary or
* permanent.
*/
class NotFoundException : BaseException {
constructor() {
this.code = "404"
this.message = "Not Found"
this.status = HttpStatus.NOT_FOUND
}
constructor(message: String?) {
this.code = "404"
this.message = message!!
this.status = HttpStatus.NOT_FOUND
}
}
package id.go.kemenag.madrasah.pmrms.auth.exception
import org.springframework.http.HttpStatus
/**
* The server understands the content type of the request entity,
* and the syntax of the request entity is correct
* but was unable to process the contained instructions.
*/
class UnProcessableEntityException : BaseException {
constructor() {
this.code = "422"
this.message = "UnProcessable Entity"
this.status = HttpStatus.UNPROCESSABLE_ENTITY
}
constructor(message: String?) {
this.code = "422"
this.message = message!!
this.status = HttpStatus.UNPROCESSABLE_ENTITY
}
constructor(message: String? = null, data: Any? = null) {
this.code = "422"
this.message = message ?: "UnProcessable Entity"
this.status = HttpStatus.UNPROCESSABLE_ENTITY
this.data = data
}
}
package id.go.kemenag.madrasah.pmrms.auth.exception
import org.springframework.http.HttpStatus
/**
*
* response status code indicates that the server cannot or will not process
* the request due to something that is perceived to be a client error
* (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
*/
class UnautorizedException : BaseException {
constructor(message: String? = "Unautorized") {
this.code = "400"
this.message = message!!
this.status = HttpStatus.UNAUTHORIZED
}
constructor(message: String? = "Unautorized", data: Any?) {
this.code = "400"
this.message = message!!
this.status = HttpStatus.UNAUTHORIZED
this.data = data
}
}
package id.go.kemenag.madrasah.pmrms.auth.exception
import org.springframework.http.HttpStatus
/**
* The 415 (Unsupported Media Type) status code indicates that the
* origin server is refusing to service the request because the payload
* is in a format not supported by this method on the target resource.
* The format problem might be due to the request's indicated
* Content-Type or Content-Encoding, or as a result of inspecting the
* data directly.
*/
class UnsupportedMediaTypeException : BaseException {
constructor() {
this.code = "415"
this.message = "Unsupported Media Type"
this.status = HttpStatus.UNSUPPORTED_MEDIA_TYPE
}
constructor(message: String?) {
this.code = "415"
this.message = message!!
this.status = HttpStatus.UNSUPPORTED_MEDIA_TYPE
}
}
package id.go.kemenag.madrasah.pmrms.auth.helpers
import id.go.kemenag.madrasah.pmrms.auth.model.response.ReturnData
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
fun responseSuccess(message: String = "Success", data: Any? = null): ResponseEntity<ReturnData> {
return ResponseEntity<ReturnData>(
ReturnData(
success = true,
message = message,
data = data
),
HttpStatus.OK
)
}
fun responseCreated(message: String = "Created", data: Any? = null): ResponseEntity<ReturnData> {
return ResponseEntity<ReturnData>(
ReturnData(
success = true,
message = message,
data = data
),
HttpStatus.CREATED
)
}
fun responseInternalServerError(
message: String = "Internal Server Error",
data: Any? = null
): ResponseEntity<ReturnData> {
return ResponseEntity<ReturnData>(
ReturnData(
success = false,
message = message,
data = data
),
HttpStatus.INTERNAL_SERVER_ERROR
)
}
fun responseNotFound(message: String = "Not Found", data: Any? = null): ResponseEntity<ReturnData> {
return ResponseEntity<ReturnData>(
ReturnData(
success = false,
message = message,
data = data
),
HttpStatus.NOT_FOUND
)
}
fun responseUnprocessableEntity(
message: String = "Unprocessable Entity",
data: Any? = null
): ResponseEntity<ReturnData> {
return ResponseEntity<ReturnData>(
ReturnData(
success = false,
message = message,
data = data
),
HttpStatus.UNPROCESSABLE_ENTITY
)
}
fun responseBadRequest(message: String = "Bad Request", data: Any? = null): ResponseEntity<ReturnData> {
return ResponseEntity<ReturnData>(
ReturnData(
success = false,
message = message,
data = data
),
HttpStatus.BAD_REQUEST
)
}
package id.go.kemenag.madrasah.pmrms.auth.interceptor
import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import com.auth0.jwt.exceptions.JWTCreationException
import com.auth0.jwt.exceptions.JWTDecodeException
import com.auth0.jwt.exceptions.JWTVerificationException
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import id.go.kemenag.madrasah.pmrms.auth.constant.*
import id.go.kemenag.madrasah.pmrms.auth.model.response.ReturnData
import id.go.kemenag.madrasah.pmrms.auth.pojo.Users
import id.go.kemenag.madrasah.pmrms.auth.repository.UserRepository
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.context.support.WebApplicationContextUtils
import org.springframework.web.util.ContentCachingRequestWrapper
import javax.servlet.Filter
import javax.servlet.FilterChain
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class TokenInterceptor : Filter {
override fun doFilter(request: ServletRequest?, response: ServletResponse?, chain: FilterChain?) {
val req = ContentCachingRequestWrapper(request as HttpServletRequest)
val res = response as HttpServletResponse
// Read the Authorization header, where the JWT token should be
val header = req.getHeader(HEADER_STRING)
// If header doesn't contain Bearer or is null will return nothing and exit
if (header == null || !header.startsWith(TOKEN_PREFIX)) {
responseException(res, "Token $VALIDATOR_MSG_REQUIRED")
return
}
var authentication: UsernamePasswordAuthenticationToken? = null
var successAuth = true
try {
authentication = getAuthentication(req)
} catch (e: JWTDecodeException) {
successAuth = false
responseException(res, e.message.toString())
} catch (e: JWTCreationException) {
successAuth = false
responseException(res, e.message.toString())
} catch (e: JWTVerificationException) {
successAuth = false
responseException(res, e.message.toString())
} catch (e: IllegalArgumentException) {
successAuth = false
responseException(res, e.message.toString())
} catch (e: Exception) {
successAuth = false
responseException(res, e.message.toString())
}
SecurityContextHolder.getContext().authentication = authentication
if (successAuth) {
chain?.doFilter(request, response)
}
}
private fun responseException(response: HttpServletResponse, message: String) {
val json = ObjectMapper().writeValueAsString(
ReturnData(
message = message
)
)
response.contentType = "application/json"
response.status = HttpServletResponse.SC_UNAUTHORIZED
response.writer.write(json)
response.writer.flush()
response.writer.close()
}
@Throws(
JWTDecodeException::class,
JWTCreationException::class,
JWTVerificationException::class,
IllegalArgumentException::class
)
private fun getAuthentication(request: HttpServletRequest): UsernamePasswordAuthenticationToken {
val token = request.getHeader(HEADER_STRING)
// parse jwt token from request and validate it internal authentication
val jwt =
JWT.require(Algorithm.HMAC512(SECRET.toByteArray())).build().verify(token.replace(TOKEN_PREFIX, ""))
return if (jwt.subject != null) { // return principal username
val audience = jwt.audience?.get(0)
var isAllowed = false
AUDIENCE_FILTER_PATH[audience]?.forEach lambda@{
if (it.contains("/*")) {
if (request.requestURI.contains(it.replace("/*", ""))) {
isAllowed = true
return@lambda
}
} else {
if (request.requestURI == it) {
isAllowed = true
return@lambda
}
}
}
if (isAllowed) {
val objectMapper = ObjectMapper()
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
val users: Users = objectMapper.readValue(jwt.subject, Users::class.java)
val servletContext = request.session.servletContext
val webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext)
val repoUser = webApplicationContext!!.getBean(UserRepository::class.java)
val checkUser = repoUser.findByIdAndActive(users.id)
if (checkUser.isPresent) {
UsernamePasswordAuthenticationToken(
objectMapper.writeValueAsString(users),
audience,
ArrayList()
)
} else {
throw Exception("User $VALIDATOR_MSG_NOT_FOUND")
}
} else {
throw Exception("User $VALIDATOR_MSG_NOT_HAVE_ACCESS")
}
} else {
throw Exception("Token $VALIDATOR_MSG_NOT_VALID")
}
}
}
package id.go.kemenag.madrasah.pmrms.auth.model.request.auth
import id.go.kemenag.madrasah.pmrms.auth.constant.VALIDATOR_MSG_REQUIRED
import id.go.kemenag.madrasah.pmrms.auth.validator.EmailValidator
import javax.validation.constraints.NotEmpty
class LoginRequest(
@field:NotEmpty(message = "Email $VALIDATOR_MSG_REQUIRED")
@field:EmailValidator
var email: String? = null,
@field:NotEmpty(message = "Password $VALIDATOR_MSG_REQUIRED")
var password: String? = null
)
package id.go.kemenag.madrasah.pmrms.auth.model.response
data class DatatableResponse(
var content: Any? = null,
var first: Boolean? = null,
var last: Boolean? = null,
var totalElements: Long? = null,
var totalPages: Int? = null
)
package id.go.kemenag.madrasah.pmrms.auth.model.response
data class ErrorMessage(
var key: String? = null,
var message: String? = null
)
package id.go.kemenag.madrasah.pmrms.auth.model.response
data class ReturnData(
var success: Boolean? = false,
var data: Any? = null,
var message: String? = null
)
package id.go.kemenag.madrasah.pmrms.auth.model.response.jwt
data class JwtAuthenticationResponse(
val accessToken: String? = null,
val tokenType: String? = null,
val expired: Long = 0,
val user: Any? = null
)
package id.go.kemenag.madrasah.pmrms.auth.pojo
import com.fasterxml.jackson.annotation.JsonFormat
import com.fasterxml.jackson.annotation.JsonIgnore
import java.util.*
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Table
@Entity
@Table(name = "users", schema = "auth")
data class Users(
@Id
@Column(name = "id")
var id: String? = UUID.randomUUID().toString(),
@Column(name = "email")
var email: String? = null,
@Column(name = "password")
@JsonIgnore
var password: String? = null,
@Column(name = "first_name")
var fullName: String? = null,
@Column(name = "last_name")
var lastName: String? = null,
@Column(name = "created_at")
@get:JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy HH:mm:ss", timezone = "GMT+7")
var createdAt: Date? = Date(),
@Column(name = "updated_at")
@get:JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy HH:mm:ss", timezone = "GMT+7")
var updatedAt: Date? = Date(),
@Column(name = "active")
@JsonIgnore
var active: Boolean? = true
)
package id.go.kemenag.madrasah.pmrms.auth.repository
import id.go.kemenag.madrasah.pmrms.auth.pojo.Users
import org.springframework.data.jpa.repository.JpaRepository
import java.util.*
interface UserRepository : JpaRepository<Users, String> {
fun findByIdAndActive(id: String?, active: Boolean = true): Optional<Users>
fun findByEmailAndActive(email: String?, active: Boolean = true): Optional<Users>
}
package id.go.kemenag.madrasah.pmrms.auth.service
import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import id.go.kemenag.madrasah.pmrms.auth.constant.EXPIRATION_TIME
import id.go.kemenag.madrasah.pmrms.auth.constant.SECRET
import id.go.kemenag.madrasah.pmrms.auth.constant.TOKEN_PREFIX
import id.go.kemenag.madrasah.pmrms.auth.exception.BadRequestException
import id.go.kemenag.madrasah.pmrms.auth.helpers.responseSuccess
import id.go.kemenag.madrasah.pmrms.auth.model.request.auth.LoginRequest
import id.go.kemenag.madrasah.pmrms.auth.model.response.ReturnData
import id.go.kemenag.madrasah.pmrms.auth.model.response.jwt.JwtAuthenticationResponse
import id.go.kemenag.madrasah.pmrms.auth.pojo.Users
import id.go.kemenag.madrasah.pmrms.auth.repository.UserRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.stereotype.Service
import java.util.*
@Service
class AuthService {
@Autowired
private lateinit var repoUser: UserRepository
fun login(request: LoginRequest): ResponseEntity<ReturnData> {
try {
val data = repoUser.findByEmailAndActive(request.email)
if (data.isPresent) {
if (BCryptPasswordEncoder().matches(request.password, data.get().password)) {
val objectMapper = ObjectMapper()
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
val user: Users =
objectMapper.readValue(objectMapper.writeValueAsString(data.get()), Users::class.java)
return responseSuccess(data = writeToken(user, "user-admin"))
}
}
throw BadRequestException(message = "Pengguna tidak diketahui")
} catch (e: Exception) {
throw e
}
}
private fun writeToken(user: Any, audience: String): JwtAuthenticationResponse {
val objectMapper = ObjectMapper()
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
val users: Users = objectMapper.readValue(objectMapper.writeValueAsString(user), Users::class.java)
val expire = Date(System.currentTimeMillis() + EXPIRATION_TIME)
val token =
JWT.create().withSubject(objectMapper.writeValueAsString(user)).withExpiresAt(expire).withAudience(audience)
.sign(Algorithm.HMAC512(SECRET.toByteArray()))
val jwtres = JwtAuthenticationResponse(
token, TOKEN_PREFIX.trim(), expire.time, users
)
return jwtres
}
}
package id.go.kemenag.madrasah.pmrms.auth.validator
import id.go.kemenag.madrasah.pmrms.auth.constant.VALIDATOR_MSG_NOT_VALID
import org.apache.commons.validator.routines.EmailValidator
import javax.validation.Constraint
import javax.validation.ConstraintValidator
import javax.validation.ConstraintValidatorContext
import javax.validation.Payload
import kotlin.reflect.KClass
@Target(AnnotationTarget.FIELD)
@MustBeDocumented
@Constraint(validatedBy = [CustomEmailValidatorConstrain::class])
annotation class EmailValidator(
val message: String = "Email $VALIDATOR_MSG_NOT_VALID",
val groups: Array<KClass<*>> = [],
val payload: Array<KClass<out Payload>> = []
)
class CustomEmailValidatorConstrain :
ConstraintValidator<id.go.kemenag.madrasah.pmrms.auth.validator.EmailValidator, String> {
override fun isValid(p0: String?, p1: ConstraintValidatorContext?): Boolean {
if (p0.isNullOrEmpty()) {
return true
} else {
if (!p0.contains("@madrasah.kemenag.go.id")) {
return false
}
}
return EmailValidator.getInstance().isValid(p0)
}
}
# SERVER CONFIG
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
spring.profiles.active=development
server.port=8080
# DATABASE CONFIG
# local
spring.datasource.url=jdbc:postgresql://localhost:5432/pmrms
spring.datasource.username=postgres
spring.datasource.password=root
# dev
#spring.datasource.url=jdbc:postgresql://128.199.84.134:15434/pmrms_db
#spring.datasource.username=postgres
#spring.datasource.password=KemInfo2021
# JPA CONFIG
spring.jpa.hibernate.ddl-auto=none
spring.jpa.generate-ddl=false
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.legacy_limit_handler=true
spring.jpa.properties.hibernate.format_sql=true
# UPLOAD CONFIG
spring.servlet.multipart.max-file-size=500MB
spring.servlet.multipart.max-request-size=500MB
# MAIl CONFIG
spring.mail.host=mail.smtp2go.com
spring.mail.port=2525
spring.mail.username=kominfo-05
spring.mail.password=eXFwenN6cm4yYmMw
spring.mail.from=no-reply@layanan.go.id
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.connectiontimeout=25000
spring.mail.properties.mail.smtp.timeout=25000
spring.mail.properties.mail.smtp.writetimeout=25000
spring.mail.properties.mail.smtp.starttls.enable=true
# APP CONFIG
app.name = PMRMS
server.max-http-header-size=10000KB
package id.go.kemenag.madrasah.pmrms.auth
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest
class PmrmsAuthApplicationTests {
@Test
fun contextLoads() {
}
}
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