Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@
ktlint_standard_import-ordering = disabled
ktlint_standard_blank-line-before-declaration = disabled
ktlint_standard_multiline-if-else = disabled
ktlint_function_signature_body_expression_wrapping = disabled
ktlint_standard_function-type-modifier-spacing = disabled
36 changes: 18 additions & 18 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

val kotestAssertionsVersion: String by properties
val kotlinVersion: String by properties
val flywayVersion: String by properties
val log4jApiKotlinVersion: String by properties
val jsonVersion: String by properties
Expand All @@ -25,9 +24,9 @@ plugins {
}

allOpen {
annotation("javax.persistence.Entity")
annotation("javax.persistence.MappedSuperclass")
annotation("javax.persistence.Embeddable")
annotation("jakarta.persistence.Entity")
annotation("jakarta.persistence.MappedSuperclass")
annotation("jakarta.persistence.Embeddable")
}

repositories {
Expand All @@ -36,7 +35,7 @@ repositories {

dependencyManagement {
imports {
mavenBom("software.amazon.awssdk:bom:2.17.198")
mavenBom("software.amazon.awssdk:bom:2.34.0")
}
}

Expand All @@ -57,7 +56,7 @@ dependencies {
implementation("org.postgresql:postgresql")
implementation("org.flywaydb:flyway-core:$flywayVersion")

implementation("com.google.firebase:firebase-admin:8.1.0")
implementation("com.google.firebase:firebase-admin:9.1.1")

implementation("com.auth0:java-jwt:3.10.3")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
Expand Down Expand Up @@ -96,15 +95,16 @@ dependencies {
testImplementation("org.testcontainers:junit-jupiter:$testContainersVersion")
testImplementation("org.testcontainers:postgresql:$testContainersVersion")
testImplementation("org.testcontainers:localstack:$testContainersVersion")
testImplementation("com.amazonaws:aws-java-sdk:1.11.808")
testImplementation("com.amazonaws:aws-java-sdk:1.12.791")
testImplementation("com.squareup.okhttp3:okhttp:$okhttp3Version")
testImplementation("com.squareup.okhttp3:mockwebserver:$okhttp3Version")
}

tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "17"
kotlin {
compilerOptions {
// apiVersion = KotlinVersion.KOTLIN_2_1
jvmTarget = JvmTarget.JVM_17
freeCompilerArgs.add("-Xjsr305=strict")
}
}

Expand Down Expand Up @@ -156,8 +156,8 @@ tasks.register<JavaExec>("ktlintFormat") {
)
}

project.exec {
commandLine = "git config core.hooksPath .githooks".split(" ")
tasks.register<Exec>("setGitHooksPath") {
commandLine("git", "config", "core.hooksPath", ".githooks")
}

tasks.named("compileKotlin") { dependsOn("ktlintCheck") }
Expand All @@ -178,9 +178,9 @@ tasks.withType<JacocoReport> {
reports {
xml.required.set(true)
html.required.set(true)
xml.outputLocation.set(file("$buildDir/jacoco/coverage.xml"))
xml.outputLocation.set(layout.buildDirectory.file("jacoco/coverage.xml"))
csv.required.set(false)
html.outputLocation.set(file("$buildDir/jacoco/html"))
html.outputLocation.set(layout.buildDirectory.dir("jacoco/html"))
}
afterEvaluate {
classDirectories.setFrom(
Expand All @@ -202,10 +202,10 @@ tasks.withType<JacocoReport> {
),
)
}
executionData.setFrom("$buildDir/jacoco/test.exec")
executionData.setFrom(layout.buildDirectory.file("jacoco/test.exec"))
}

task<Test>("integrationTest") {
tasks.register<Test>("integrationTest") {
useJUnitPlatform { includeTags("integration-test") }
mustRunAfter(tasks["test"])
group = "Verification"
Expand Down
10 changes: 5 additions & 5 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
kotlin.code.style=official

springBootVersion=2.5.9
springDependencyVersion=1.0.11.RELEASE
springBootVersion=3.2.0
springDependencyVersion=1.1.7
kotlinVersion=2.1.20
kotlinxCoroutinesCoreVersion=1.6.0
flywayVersion=6.5.5
junitVersion=5.3.1
flywayVersion=9.22.0
junitVersion=5.10.0
mockkVersion=1.13.17
kotestAssertionsVersion=5.9.1
jsonVersion=20210307
log4jApiKotlinVersion=1.1.0
springCloudContractWiremockVersion=3.1.1
springCloudContractWiremockVersion=5.0.0-M1
testContainersVersion=1.15.1
okhttp3Version=4.10.0
springDocOpenApiVersion=1.6.12
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse

@Component
class FirebaseTokenAuthenticationFilter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import org.apache.logging.log4j.kotlin.logger
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse

@Component
class RememberLastVisitFilter(
Expand Down
19 changes: 10 additions & 9 deletions src/main/kotlin/com/epam/brn/config/AwsConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,15 @@ class AwsConfig(
val contentTypeStartsWith: Pair<String, String> = "Content-Type" to contentTypeStartsWith
val metaTagStartsWith: Pair<String, String> = "x-amz-meta-tag" to metaTagStartsWith

override fun toString(): String = "Conditions(date='$date'," +
" bucket=$bucket," +
" acl=$acl, uuid=$uuid," +
" serverSideEncryption=$serverSideEncryption," +
" credential=$credential, algorithm=$algorithm," +
" dateTime=$dateTime, expiration=$expiration," +
" uploadKey=$uploadKey, successActionRedirect=$successActionRedirect," +
" contentTypeStartsWith=$contentTypeStartsWith," +
" metaTagStartsWith=$metaTagStartsWith, uploadKey=$uploadKey)"
override fun toString(): String =
"Conditions(date='$date'," +
" bucket=$bucket," +
" acl=$acl, uuid=$uuid," +
" serverSideEncryption=$serverSideEncryption," +
" credential=$credential, algorithm=$algorithm," +
" dateTime=$dateTime, expiration=$expiration," +
" uploadKey=$uploadKey, successActionRedirect=$successActionRedirect," +
" contentTypeStartsWith=$contentTypeStartsWith," +
" metaTagStartsWith=$metaTagStartsWith, uploadKey=$uploadKey)"
}
}
16 changes: 9 additions & 7 deletions src/main/kotlin/com/epam/brn/config/JpaAuditConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ import java.util.Optional
)
class JpaAuditConfig {
@Bean
fun dateTimeProvider(dateTimeService: TimeService): DateTimeProvider = DateTimeProvider {
Optional.of(dateTimeService.now())
}
fun dateTimeProvider(dateTimeService: TimeService): DateTimeProvider =
DateTimeProvider {
Optional.of(dateTimeService.now())
}

@Bean
fun userContextProvider(userAccountService: UserAccountService): AuditorAware<String> = AuditorAware<String> {
val authentication = SecurityContextHolder.getContext().authentication
Optional.of(if (authentication != null) authentication.name else "InitialDataLoader")
}
fun userContextProvider(userAccountService: UserAccountService): AuditorAware<String> =
AuditorAware<String> {
val authentication = SecurityContextHolder.getContext().authentication
Optional.of(if (authentication != null) authentication.name else "InitialDataLoader")
}
}
68 changes: 35 additions & 33 deletions src/main/kotlin/com/epam/brn/config/SwaggerConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,50 +7,52 @@ import org.springdoc.core.customizers.OpenApiCustomiser
import org.springdoc.core.customizers.OperationCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import javax.annotation.security.RolesAllowed
import jakarta.annotation.security.RolesAllowed

@Configuration
class SwaggerConfig {
@Bean
fun openApi() = OpenAPI().info(apiInfo())

private fun apiInfo() = Info()
.title("Brain Up project")
.description("REST API for brn")
.contact(
Contact()
.name("Elena.Moshnikova")
.url("https://t.me/ElenaLovesSpb")
.email("brainupproject@yandex.ru"),
)
private fun apiInfo() =
Info()
.title("Brain Up project")
.description("REST API for brn")
.contact(
Contact()
.name("Elena.Moshnikova")
.url("https://t.me/ElenaLovesSpb")
.email("brainupproject@yandex.ru"),
)

@Bean
fun rolesAllowedCustomizer(): OperationCustomizer? = OperationCustomizer { operation, handlerMethod ->
var allowedRoles: Array<String>? = null
var rolesAllowedAnnotation = handlerMethod.getMethodAnnotation(RolesAllowed::class.java)
if (rolesAllowedAnnotation != null) {
allowedRoles = rolesAllowedAnnotation.value
} else {
rolesAllowedAnnotation = handlerMethod.method.declaringClass.getAnnotation(RolesAllowed::class.java)
if (rolesAllowedAnnotation != null)
fun rolesAllowedCustomizer(): OperationCustomizer? =
OperationCustomizer { operation, handlerMethod ->
var allowedRoles: Array<String>? = null
var rolesAllowedAnnotation = handlerMethod.getMethodAnnotation(RolesAllowed::class.java)
if (rolesAllowedAnnotation != null) {
allowedRoles = rolesAllowedAnnotation.value
} else {
rolesAllowedAnnotation = handlerMethod.method.declaringClass.getAnnotation(RolesAllowed::class.java)
if (rolesAllowedAnnotation != null)
allowedRoles = rolesAllowedAnnotation.value
}

val sb = StringBuilder("Roles: ")
if (allowedRoles != null)
sb.append("**${allowedRoles.joinToString(",")}**")
else
sb.append("**PUBLIC**")

operation.description?.let {
sb.append("<br/>")
sb.append(it)
}

operation.description = sb.toString()
operation
}

val sb = StringBuilder("Roles: ")
if (allowedRoles != null)
sb.append("**${allowedRoles.joinToString(",")}**")
else
sb.append("**PUBLIC**")

operation.description?.let {
sb.append("<br/>")
sb.append(it)
}

operation.description = sb.toString()
operation
}

@Bean
fun sortTagsCustomiser(): OpenApiCustomiser = OpenApiCustomiser { openApi -> openApi.tags.sortBy { it.name } }
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,63 @@ package com.epam.brn.config
import com.epam.brn.auth.filter.FirebaseTokenAuthenticationFilter
import com.epam.brn.auth.filter.RememberLastVisitFilter
import com.epam.brn.enums.BrnRole
import com.epam.brn.service.BrainUpUserDetailsService
import jakarta.servlet.http.HttpServletResponse
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
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.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.access.AccessDeniedHandler
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import javax.servlet.http.HttpServletResponse

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)
class WebSecurityBasicConfiguration(
private val firebaseTokenAuthenticationFilter: FirebaseTokenAuthenticationFilter,
private val rememberLastVisitFilter: RememberLastVisitFilter,
) : WebSecurityConfigurerAdapter() {
@Throws(Exception::class)
override fun configure(http: HttpSecurity) {
private val buUserDetailsService: BrainUpUserDetailsService,
) {
@Bean
@Throws(java.lang.Exception::class)
fun filterChain(http: HttpSecurity): SecurityFilterChain? =
http
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf { it.disable() }
.sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) }
.addFilterBefore(firebaseTokenAuthenticationFilter, UsernamePasswordAuthenticationFilter::class.java)
.addFilterAfter(rememberLastVisitFilter, UsernamePasswordAuthenticationFilter::class.java)
.authorizeRequests()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**")
.hasRole(BrnRole.ADMIN)
.and()
.formLogin()
.disable()
.httpBasic()
.disable()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint())
.accessDeniedHandler(accessDeniedHandler())
}
.userDetailsService(buUserDetailsService)
.authorizeHttpRequests {
it.requestMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**").hasRole(BrnRole.ADMIN)
}.formLogin { it.disable() }
.httpBasic { it.disable() }
.exceptionHandling { it.authenticationEntryPoint(authenticationEntryPoint()) }
.build()

@Bean
fun accessDeniedHandler(): AccessDeniedHandler? = AccessDeniedHandler { _, response: HttpServletResponse, _ ->
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied")
}
fun accessDeniedHandler(): AccessDeniedHandler? =
AccessDeniedHandler { _, response: HttpServletResponse, _ ->
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied")
}

@Bean
fun authenticationEntryPoint(): AuthenticationEntryPoint? = AuthenticationEntryPoint { _, response: HttpServletResponse, _ ->
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized")
}
fun authenticationEntryPoint(): AuthenticationEntryPoint? =
AuthenticationEntryPoint { _, response: HttpServletResponse, _ ->
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized")
}

@Bean
fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder()

@Bean
fun brnAuthenticationManager(): AuthenticationManager = super.authenticationManagerBean()
fun brnAuthenticationManager(authenticationConfiguration: AuthenticationConfiguration): AuthenticationManager =
authenticationConfiguration.authenticationManager
}
Loading
Loading