mirror of https://github.com/usbharu/Hideout.git
commit
bd219b62e1
|
@ -29,6 +29,8 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.PAT }}
|
||||||
|
|
||||||
- name: Gradle Wrapper Validation
|
- name: Gradle Wrapper Validation
|
||||||
uses: gradle/actions/wrapper-validation@v4
|
uses: gradle/actions/wrapper-validation@v4
|
||||||
|
@ -55,6 +57,8 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.PAT }}
|
||||||
|
|
||||||
- name: Set up JDK 21
|
- name: Set up JDK 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
|
@ -101,6 +105,7 @@ jobs:
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.head_ref }}
|
ref: ${{ github.head_ref }}
|
||||||
|
token: '${{ secrets.PAT }}'
|
||||||
|
|
||||||
- name: Set up JDK 21
|
- name: Set up JDK 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
|
|
|
@ -48,3 +48,4 @@ out/
|
||||||
/hideout-core/files/
|
/hideout-core/files/
|
||||||
/hideout-core/.kotlin/sessions/
|
/hideout-core/.kotlin/sessions/
|
||||||
/hideout-mastodon/.kotlin/sessions/
|
/hideout-mastodon/.kotlin/sessions/
|
||||||
|
/http-client.private.env.json
|
||||||
|
|
|
@ -74,6 +74,7 @@ val os = org.gradle.nativeplatform.platform.internal
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
developmentOnly(libs.h2db)
|
developmentOnly(libs.h2db)
|
||||||
|
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||||
detektPlugins(libs.detekt.formatting)
|
detektPlugins(libs.detekt.formatting)
|
||||||
|
|
||||||
implementation(libs.bundles.exposed)
|
implementation(libs.bundles.exposed)
|
||||||
|
@ -152,6 +153,12 @@ configurations.matching { it.name == "detekt" }.all {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//tasks{
|
||||||
|
// bootRun {
|
||||||
|
// sourceResources(sourceSets.main.get())
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
tasks.withType<io.gitlab.arturbosch.detekt.Detekt> {
|
tasks.withType<io.gitlab.arturbosch.detekt.Detekt> {
|
||||||
exclude("**/generated/**")
|
exclude("**/generated/**")
|
||||||
doFirst {
|
doFirst {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import com.nimbusds.jose.jwk.source.JWKSource
|
||||||
import com.nimbusds.jose.proc.SecurityContext
|
import com.nimbusds.jose.proc.SecurityContext
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.HideoutUserDetails
|
import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.HideoutUserDetails
|
||||||
import dev.usbharu.hideout.util.RsaUtil
|
import dev.usbharu.hideout.util.RsaUtil
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
|
@ -50,6 +51,10 @@ import org.springframework.security.oauth2.server.authorization.token.JwtEncodin
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer
|
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer
|
||||||
import org.springframework.security.web.SecurityFilterChain
|
import org.springframework.security.web.SecurityFilterChain
|
||||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
|
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
|
||||||
|
import java.security.KeyPairGenerator
|
||||||
|
import java.security.interfaces.RSAPrivateKey
|
||||||
|
import java.security.interfaces.RSAPublicKey
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity(debug = false)
|
@EnableWebSecurity(debug = false)
|
||||||
|
@ -126,17 +131,54 @@ class SecurityConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun loadJwkSource(jwkConfig: JwkConfig): JWKSource<SecurityContext> {
|
fun loadJwkSource(jwkConfig: JwkConfig, applicationConfig: ApplicationConfig): JWKSource<SecurityContext> {
|
||||||
val rsaKey = RSAKey.Builder(RsaUtil.decodeRsaPublicKey(jwkConfig.publicKey))
|
if (jwkConfig.keyId == null) {
|
||||||
.privateKey(RsaUtil.decodeRsaPrivateKey(jwkConfig.privateKey)).keyID(jwkConfig.keyId).build()
|
logger.error("hideout.security.jwt.keyId is null.")
|
||||||
|
}
|
||||||
|
if (jwkConfig.publicKey == null) {
|
||||||
|
logger.error("hideout.security.jwt.publicKey is null.")
|
||||||
|
}
|
||||||
|
if (jwkConfig.privateKey == null) {
|
||||||
|
logger.error("hideout.security.jwt.privateKey is null.")
|
||||||
|
}
|
||||||
|
if (jwkConfig.keyId == null || jwkConfig.publicKey == null || jwkConfig.privateKey == null) {
|
||||||
|
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||||
|
keyPairGenerator.initialize(applicationConfig.keySize)
|
||||||
|
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
||||||
|
|
||||||
|
jwkConfig.keyId = UUID.randomUUID().toString()
|
||||||
|
jwkConfig.publicKey = RsaUtil.encodeRsaPublicKey(generateKeyPair.public as RSAPublicKey)
|
||||||
|
jwkConfig.privateKey = RsaUtil.encodeRsaPrivateKey(generateKeyPair.private as RSAPrivateKey)
|
||||||
|
logger.error(
|
||||||
|
"""
|
||||||
|
|==============
|
||||||
|
|==============
|
||||||
|
|
|
||||||
|
|**Write the following settings in application.yml**
|
||||||
|
|
|
||||||
|
|hideout:
|
||||||
|
| security:
|
||||||
|
| jwt:
|
||||||
|
| keyId: ${jwkConfig.keyId}
|
||||||
|
| publicKey: ${jwkConfig.publicKey}
|
||||||
|
| privateKey: ${jwkConfig.privateKey}
|
||||||
|
|
|
||||||
|
|==============
|
||||||
|
|==============
|
||||||
|
""".trimMargin()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val rsaKey = RSAKey.Builder(RsaUtil.decodeRsaPublicKey(jwkConfig.publicKey!!))
|
||||||
|
.privateKey(RsaUtil.decodeRsaPrivateKey(jwkConfig.privateKey!!)).keyID(jwkConfig.keyId).build()
|
||||||
return ImmutableJWKSet(JWKSet(rsaKey))
|
return ImmutableJWKSet(JWKSet(rsaKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConfigurationProperties("hideout.security.jwt")
|
@ConfigurationProperties("hideout.security.jwt")
|
||||||
data class JwkConfig(
|
data class JwkConfig(
|
||||||
val keyId: String,
|
var keyId: String?,
|
||||||
val publicKey: String,
|
var publicKey: String?,
|
||||||
val privateKey: String,
|
var privateKey: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -195,4 +237,8 @@ class SecurityConfig {
|
||||||
|
|
||||||
return roleHierarchyImpl
|
return roleHierarchyImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(SecurityConfig::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,4 +44,12 @@ object RsaUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decodeRsaPrivateKey(encoded: String): RSAPrivateKey = decodeRsaPrivateKey(Base64Util.decode(encoded))
|
fun decodeRsaPrivateKey(encoded: String): RSAPrivateKey = decodeRsaPrivateKey(Base64Util.decode(encoded))
|
||||||
|
|
||||||
|
fun encodeRsaPublicKey(publicKey: RSAPublicKey): String {
|
||||||
|
return Base64Util.encode(publicKey.encoded)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun encodeRsaPrivateKey(privateKey: RSAPrivateKey): String {
|
||||||
|
return Base64Util.encode(privateKey.encoded)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
hideout:
|
||||||
|
url: "http://localhost:8081"
|
||||||
|
private: true
|
||||||
|
debug:
|
||||||
|
trace-query-exception: true
|
||||||
|
trace-query-call: true
|
||||||
|
spring:
|
||||||
|
devtools:
|
||||||
|
livereload:
|
||||||
|
enabled: true
|
||||||
|
restart:
|
||||||
|
enabled: true
|
||||||
|
data:
|
||||||
|
mongodb:
|
||||||
|
auto-index-creation: true
|
||||||
|
host: localhost
|
||||||
|
port: 27017
|
||||||
|
database: hideout
|
||||||
|
datasource:
|
||||||
|
driver-class-name: org.postgresql.Driver
|
||||||
|
url: "jdbc:postgresql:hideout"
|
||||||
|
username: "postgres"
|
||||||
|
password: "password"
|
||||||
|
servlet:
|
||||||
|
multipart:
|
||||||
|
max-file-size: 40MB
|
||||||
|
max-request-size: 40MB
|
||||||
|
threads:
|
||||||
|
virtual:
|
||||||
|
enabled: true
|
||||||
|
messages:
|
||||||
|
basename: messages.hideout-web-messages
|
||||||
|
thymeleaf:
|
||||||
|
cache: false
|
||||||
|
server:
|
||||||
|
tomcat:
|
||||||
|
basedir: tomcat
|
||||||
|
accesslog:
|
||||||
|
enabled: true
|
||||||
|
max-http-form-post-size: 40MB
|
||||||
|
max-swallow-size: 40MB
|
||||||
|
port: 8081
|
|
@ -1,23 +1,7 @@
|
||||||
#file: noinspection SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection
|
#file: noinspection SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection
|
||||||
hideout:
|
hideout:
|
||||||
url: "https://test-hideout-dev.usbharu.dev"
|
url: "https://test-hideout-dev.usbharu.dev"
|
||||||
use-mongodb: true
|
|
||||||
owl:
|
|
||||||
producer:
|
|
||||||
standalone: embedded
|
|
||||||
security:
|
|
||||||
jwt:
|
|
||||||
generate: true
|
|
||||||
key-id: a
|
|
||||||
private-key: "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKjMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvuNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulgp2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlRZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwiVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskVlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83HmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwYdgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cwta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2TN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPvt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDUAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISLDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnKxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEAmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfzet6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhrVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicDTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cncdn/RsYEONbwQSjIfMPkvxF+8HQ=="
|
|
||||||
public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyehkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdgcKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbcmwIDAQAB"
|
|
||||||
private: true
|
private: true
|
||||||
debug:
|
|
||||||
trace-query-exception: true
|
|
||||||
trace-query-call: true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
data:
|
data:
|
||||||
|
@ -26,12 +10,6 @@ spring:
|
||||||
host: localhost
|
host: localhost
|
||||||
port: 27017
|
port: 27017
|
||||||
database: hideout
|
database: hideout
|
||||||
jmx:
|
|
||||||
enabled: false
|
|
||||||
jackson:
|
|
||||||
serialization:
|
|
||||||
WRITE_DATES_AS_TIMESTAMPS: false
|
|
||||||
default-property-inclusion: always
|
|
||||||
datasource:
|
datasource:
|
||||||
driver-class-name: org.postgresql.Driver
|
driver-class-name: org.postgresql.Driver
|
||||||
url: "jdbc:postgresql:hideout"
|
url: "jdbc:postgresql:hideout"
|
||||||
|
@ -41,9 +19,6 @@ spring:
|
||||||
multipart:
|
multipart:
|
||||||
max-file-size: 40MB
|
max-file-size: 40MB
|
||||||
max-request-size: 40MB
|
max-request-size: 40MB
|
||||||
h2:
|
|
||||||
console:
|
|
||||||
enabled: true
|
|
||||||
threads:
|
threads:
|
||||||
virtual:
|
virtual:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"dev": {
|
||||||
|
"name": "value",
|
||||||
|
"Security": {
|
||||||
|
"Auth": {
|
||||||
|
"auth-id": {
|
||||||
|
"Type": "OAuth2",
|
||||||
|
"Grant Type": "Authorization Code",
|
||||||
|
"Client ID": "{{client_id}}",
|
||||||
|
"Client Secret": "{{client_secret}}",
|
||||||
|
"Redirect URL": "https://example.com",
|
||||||
|
"Token URL": "http://{{host}}/oauth/token",
|
||||||
|
"Auth URL": "http://{{host}}/oauth/authorize",
|
||||||
|
"Scope": "write read"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
POST http://{{host}}/api/v1/apps
|
||||||
|
Accept: application/json
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"client_name": "test-client",
|
||||||
|
"redirect_uris": "https://example.com",
|
||||||
|
"scopes": "write read"
|
||||||
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
GET http://{{host}}/api/v1/accounts/verify_credentials
|
||||||
|
Authorization: Bearer {{$auth.token("auth-id")}}
|
Loading…
Reference in New Issue