mirror of https://github.com/usbharu/Hideout.git
commit
bd219b62e1
|
@ -29,6 +29,8 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
|
||||
- name: Gradle Wrapper Validation
|
||||
uses: gradle/actions/wrapper-validation@v4
|
||||
|
@ -55,6 +57,8 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
|
@ -101,6 +105,7 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
token: '${{ secrets.PAT }}'
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
|
|
|
@ -48,3 +48,4 @@ out/
|
|||
/hideout-core/files/
|
||||
/hideout-core/.kotlin/sessions/
|
||||
/hideout-mastodon/.kotlin/sessions/
|
||||
/http-client.private.env.json
|
||||
|
|
|
@ -74,6 +74,7 @@ val os = org.gradle.nativeplatform.platform.internal
|
|||
|
||||
dependencies {
|
||||
developmentOnly(libs.h2db)
|
||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||
detektPlugins(libs.detekt.formatting)
|
||||
|
||||
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> {
|
||||
exclude("**/generated/**")
|
||||
doFirst {
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.nimbusds.jose.jwk.source.JWKSource
|
|||
import com.nimbusds.jose.proc.SecurityContext
|
||||
import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.HideoutUserDetails
|
||||
import dev.usbharu.hideout.util.RsaUtil
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
import org.springframework.context.annotation.Bean
|
||||
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.web.SecurityFilterChain
|
||||
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
|
||||
@EnableWebSecurity(debug = false)
|
||||
|
@ -126,17 +131,54 @@ class SecurityConfig {
|
|||
}
|
||||
|
||||
@Bean
|
||||
fun loadJwkSource(jwkConfig: JwkConfig): JWKSource<SecurityContext> {
|
||||
val rsaKey = RSAKey.Builder(RsaUtil.decodeRsaPublicKey(jwkConfig.publicKey))
|
||||
.privateKey(RsaUtil.decodeRsaPrivateKey(jwkConfig.privateKey)).keyID(jwkConfig.keyId).build()
|
||||
fun loadJwkSource(jwkConfig: JwkConfig, applicationConfig: ApplicationConfig): JWKSource<SecurityContext> {
|
||||
if (jwkConfig.keyId == null) {
|
||||
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))
|
||||
}
|
||||
|
||||
@ConfigurationProperties("hideout.security.jwt")
|
||||
data class JwkConfig(
|
||||
val keyId: String,
|
||||
val publicKey: String,
|
||||
val privateKey: String,
|
||||
var keyId: String?,
|
||||
var publicKey: String?,
|
||||
var privateKey: String?,
|
||||
)
|
||||
|
||||
@Bean
|
||||
|
@ -195,4 +237,8 @@ class SecurityConfig {
|
|||
|
||||
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 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
|
||||
hideout:
|
||||
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
|
||||
debug:
|
||||
trace-query-exception: true
|
||||
trace-query-call: true
|
||||
|
||||
|
||||
|
||||
|
||||
spring:
|
||||
data:
|
||||
|
@ -26,12 +10,6 @@ spring:
|
|||
host: localhost
|
||||
port: 27017
|
||||
database: hideout
|
||||
jmx:
|
||||
enabled: false
|
||||
jackson:
|
||||
serialization:
|
||||
WRITE_DATES_AS_TIMESTAMPS: false
|
||||
default-property-inclusion: always
|
||||
datasource:
|
||||
driver-class-name: org.postgresql.Driver
|
||||
url: "jdbc:postgresql:hideout"
|
||||
|
@ -41,9 +19,6 @@ spring:
|
|||
multipart:
|
||||
max-file-size: 40MB
|
||||
max-request-size: 40MB
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
threads:
|
||||
virtual:
|
||||
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