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
Binary file added .DS_Store
Binary file not shown.
156 changes: 138 additions & 18 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,63 +1,183 @@
<?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">
<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>3.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
<relativePath/>
</parent>

<groupId>com.coded.spring</groupId>
<artifactId>Ordering</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Kotlin.SpringbootV2</name>
<description>Kotlin.SpringbootV2</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>

<properties>
<java.version>21</java.version>
<kotlin.version>1.9.25</kotlin.version>
</properties>

<dependencies>
<!-- Spring Web & JPA -->
<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>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- Password encoder -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
</dependency>

<!-- Database Drivers -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>

<!-- Kotlin support -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>

<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>

<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<scope>runtime</scope>
<version>0.11.5</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<scope>runtime</scope>
<version>0.11.5</version>
</dependency>

<!-- Swagger / OpenAPI -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version>
</dependency>

<!-- Jakarta Inject -->
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
</dependency>

<!-- Hazelcast Cache -->
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>5.5.0</version>
</dependency>

<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit5</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>7.11.2</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>7.11.2</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.3.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-path</artifactId>
<version>5.3.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-schema-validator</artifactId>
<version>5.3.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>

</dependencies>

<build>
Expand Down
Binary file added src/.DS_Store
Binary file not shown.
Binary file added src/main/.DS_Store
Binary file not shown.
Binary file added src/main/kotlin/.DS_Store
Binary file not shown.
Binary file added src/main/kotlin/com/.DS_Store
Binary file not shown.
Binary file added src/main/kotlin/com/coded/.DS_Store
Binary file not shown.
Binary file added src/main/kotlin/com/coded/spring/.DS_Store
Binary file not shown.
Binary file not shown.
13 changes: 13 additions & 0 deletions src/main/kotlin/com/coded/spring/ordering/AppProperties.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.coded.spring.ordering

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Configuration

@Configuration
@ConfigurationProperties
class AppProperties {
lateinit var companyName: String
var festiveMode: Boolean = false
var festiveMessage: String = "Eidkom Mubarak"
var festiveDiscount: Int = 20
}
7 changes: 7 additions & 0 deletions src/main/kotlin/com/coded/spring/ordering/Application.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.coded.spring.ordering

import com.hazelcast.config.Config;
import com.hazelcast.core.Hazelcast
import com.hazelcast.core.HazelcastInstance
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

Expand All @@ -8,4 +11,8 @@ class Application

fun main(args: Array<String>) {
runApplication<Application>(*args)
helloWorldConfig.getMapConfig("pets").setTimeToLiveSeconds(5)
}

val helloWorldConfig = Config("hello-world-cache")
val serverCache: HazelcastInstance = Hazelcast.newHazelcastInstance(helloWorldConfig)
34 changes: 34 additions & 0 deletions src/main/kotlin/com/coded/spring/ordering/InitUserRunner.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.coded.spring.ordering

import com.coded.spring.ordering.model.Roles
import com.coded.spring.ordering.model.User
import com.coded.spring.ordering.repository.*
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import org.springframework.security.crypto.password.PasswordEncoder

// @SpringBootApplication
class InitUserRunner {
@Bean
fun initUsers(userRepository: UserRepository, passwordEncoder: PasswordEncoder) = CommandLineRunner {
val user = User(
name = "HelloUser",
username = "testuser",
password = passwordEncoder.encode("password123"),
age = 18,
role = Roles.USER
)
if (userRepository.findByUsername(user.username) == null) {
println("Creating user ${user.username}")
userRepository.save(user)
} else {
println("User ${user.username} already exists")
}
}
}

fun main(args: Array<String>) {
runApplication<Application>(*args).close()
}
37 changes: 37 additions & 0 deletions src/main/kotlin/com/coded/spring/ordering/LoggingFilter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.coded.spring.ordering

import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
import org.springframework.web.util.ContentCachingRequestWrapper
import org.springframework.web.util.ContentCachingResponseWrapper

@Component
class LoggingFilter: OncePerRequestFilter(){
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
val cachedRequest = ContentCachingRequestWrapper(request)
val cachedResponse = ContentCachingResponseWrapper(response)

filterChain.doFilter(cachedRequest, cachedResponse)

logRequest(cachedRequest)
logResponse(cachedResponse)
cachedResponse.copyBodyToResponse()
}

private fun logRequest(request: ContentCachingRequestWrapper) {
val requestBody = String(request.contentAsByteArray)
logger.info("Request: method=${request.method}, uri=${request.requestURI}, body=$requestBody")
}

private fun logResponse(response: ContentCachingResponseWrapper) {
val responseBody = String(response.contentAsByteArray)
logger.info("Response: status=${response.status}, body=$responseBody")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.coded.spring.ordering.authentication

import org.springframework.security.core.userdetails.*
import com.coded.spring.ordering.repository.UserRepository
import org.springframework.stereotype.Service

@Service
class CustomUserDetailsService(
private val usersRepository: UserRepository) : UserDetailsService {
override fun loadUserByUsername(username: String): UserDetails {
val user = usersRepository.findByUsername(username) ?: throw UsernameNotFoundException("User not found")

return User.builder()
.username(user.username)
.password(user.password)
.roles(user.role.toString())
.build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.coded.spring.ordering.authentication

import com.coded.spring.ordering.authentication.jwt.JwtAuthenticationFilter
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
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.core.userdetails.UserDetailsService
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter


@Configuration
@EnableWebSecurity
class SecurityConfig(
private val jwtAuthFilter: JwtAuthenticationFilter,
private val userDetailsService: UserDetailsService
) {

@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http.csrf { it.disable() }
.authorizeHttpRequests {
it
.requestMatchers("/users/create").permitAll()
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/hello").permitAll()
.requestMatchers("/users/getAll").permitAll()
.requestMatchers("/users/**").hasRole("ADMIN")
.requestMatchers("/profile/**").authenticated()
.requestMatchers("/menu/**").authenticated()

.anyRequest().permitAll()
}
.sessionManagement {
it.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}
.authenticationProvider(authenticationProvider())
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter::class.java)

return http.build()
}

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

@Bean
fun authenticationManager(config: AuthenticationConfiguration): AuthenticationManager =
config.authenticationManager

@Bean
fun authenticationProvider(): AuthenticationProvider {
val provider = DaoAuthenticationProvider()
provider.setUserDetailsService(userDetailsService)
provider.setPasswordEncoder(passwordEncoder())
return provider
}
}
Loading