-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Systembruker konfigurasjon
- Loading branch information
Showing
5 changed files
with
162 additions
and
136 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,145 +1,28 @@ | ||
package no.nav.helsearbeidsgiver.maskinporten | ||
|
||
import com.nimbusds.jose.JOSEObjectType | ||
import com.nimbusds.jose.JWSAlgorithm | ||
import com.nimbusds.jose.JWSHeader | ||
import com.nimbusds.jose.crypto.RSASSASigner | ||
import com.nimbusds.jose.jwk.RSAKey | ||
import com.nimbusds.jwt.JWTClaimsSet | ||
import com.nimbusds.jwt.SignedJWT | ||
import java.security.KeyFactory | ||
import java.security.PrivateKey | ||
import java.security.spec.PKCS8EncodedKeySpec | ||
import java.time.Instant | ||
import java.util.Base64 | ||
import java.util.Date | ||
import java.util.UUID | ||
|
||
interface MaskinportenClientConfig { | ||
val scope: String | ||
val clientId: String | ||
val issuer: String | ||
val endpoint: String | ||
val additionalClaims: Map<String, Any>? | ||
fun getJwtAssertion(): String | ||
fun currentTime(): Date = Date.from(Instant.now()) | ||
} | ||
|
||
/** | ||
* MaskinportenClientConfigPkey er en implementasjon av MaskinportenClientConfig med privatekey som autentiseringsmetode for maskinporten | ||
* | ||
* @param kid Det er id-en til nøkkelen key-id (kid). | ||
* @param privateKey Det er privatekey som skal brukes til å signere JWT tokenet | ||
* @param clientId Din egen client_id. Sendes videre til Maskinporten som en issuer claim. | ||
* @param issuer Issuer-identifikatoren til Maskinporten. 'https://maskinporten.no/' i produksjon. Sendes videre til Maskinporten som en audience claim. | ||
* @param consumerOrgNr Det er organisasjonsnummeret til virksomheten som skal bruke maskinporten på vegne av | ||
* @param scope Space-separert liste over scopes som klienten forespør. | ||
* @param endpoint Det er endepunktet til maskinporten | ||
* | ||
*/ | ||
class MaskinportenClientConfigPkey( | ||
val kid: String, | ||
val privateKey: String, | ||
override val clientId: String, | ||
override val issuer: String, | ||
val consumerOrgNr: String, | ||
override val scope: String, | ||
override val endpoint: String | ||
) : MaskinportenClientConfig { | ||
|
||
private fun loadPrivateKey(key: String): PrivateKey { | ||
val keyText = | ||
key | ||
.replace("-----BEGIN PRIVATE KEY-----", "") | ||
.replace("-----END PRIVATE KEY-----", "") | ||
.replace("\n", "") | ||
.replace("\\s".toRegex(), "") | ||
|
||
val encoded = Base64.getDecoder().decode(keyText) | ||
return KeyFactory | ||
.getInstance("RSA") | ||
.generatePrivate(PKCS8EncodedKeySpec(encoded)) | ||
} | ||
|
||
override fun getJwtAssertion(): String { | ||
val currentTimestamp = System.currentTimeMillis() / 1000 | ||
|
||
val header = | ||
JWSHeader | ||
.Builder(JWSAlgorithm.RS256) | ||
.keyID(kid) | ||
.type(JOSEObjectType.JWT) | ||
.build() | ||
|
||
val claims = | ||
JWTClaimsSet | ||
.Builder() | ||
.issuer(clientId) | ||
.audience(issuer) | ||
.issueTime(Date(currentTimestamp * 1000)) | ||
.expirationTime(Date((currentTimestamp + 60) * 1000)) | ||
.claim("scope", scope) | ||
.claim("consumer_org", consumerOrgNr) | ||
.jwtID(UUID.randomUUID().toString()) | ||
.build() | ||
|
||
val signer = RSASSASigner(loadPrivateKey(privateKey)) | ||
val signedJWT = SignedJWT(header, claims) | ||
signedJWT.sign(signer) | ||
|
||
return signedJWT.serialize() | ||
} | ||
} | ||
|
||
/** | ||
* MaskinportenSimpleAssertion er en implementasjon av MaskinportenClientConfig med assertion som autentiseringsmetode | ||
* for maskinporten Denne brukes for å authentisere mot maskinporten for eksample for Altinn | ||
* | ||
* @param scope Space-separert liste over scopes som klienten forespør. | ||
* @param clientId issuer - Din egen client_id. | ||
* @param issuer Audience - issuer-identifikatoren til Maskinporten. Verdi for aktuelt miljø finner du på .well-known-endpunkt. | ||
* @param endpoint Endepunktet til maskinporten | ||
* @param clientJwk JWK som skal brukes til å signere JWT tokenet | ||
* | ||
*/ | ||
class MaskinportenClientConfigSimpleAssertion( | ||
override val scope: String, | ||
override val clientId: String, | ||
override val issuer: String, | ||
override val endpoint: String, | ||
val clientJwk: String | ||
) : MaskinportenClientConfig { | ||
|
||
private val rsaKey: RSAKey by lazy { | ||
try { | ||
RSAKey.parse(clientJwk) | ||
} catch (e: Exception) { | ||
throw IllegalArgumentException("Invalid JWK format", e) | ||
} | ||
} | ||
private val signer: RSASSASigner by lazy { | ||
RSASSASigner(rsaKey.toPrivateKey()) | ||
} | ||
private val header: JWSHeader by lazy { | ||
JWSHeader.Builder(JWSAlgorithm.RS256) | ||
.keyID(rsaKey.keyID) | ||
.type(JOSEObjectType.JWT) | ||
.build() | ||
} | ||
|
||
private fun currentTime(): Date = Date.from(Instant.now()) | ||
|
||
private fun claims(): JWTClaimsSet { | ||
val now = currentTime() | ||
return JWTClaimsSet.Builder() | ||
.issuer(clientId) | ||
.audience(issuer) | ||
.issueTime(now) | ||
.claim("scope", scope) | ||
.expirationTime(Date.from(now.toInstant().plusSeconds(60))) | ||
.jwtID(UUID.randomUUID().toString()) | ||
.build() | ||
} | ||
|
||
override fun getJwtAssertion(): String { | ||
return SignedJWT(header, claims()).apply { sign(signer) }.serialize() | ||
} | ||
} | ||
fun getConsumerOrgClaim(orgnr: String) = mapOf("consumer_orgno" to orgnr) | ||
|
||
fun getSystembrukerClaim(orgNr: String) = mapOf( | ||
"authorization_details" to listOf( | ||
mapOf( | ||
"type" to "urn:altinn:systemuser", | ||
"systemuser_org" to mapOf( | ||
"authority" to "iso6523-actorid-upis", | ||
"ID" to "0192:$orgNr" | ||
) | ||
) | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package no.nav.helsearbeidsgiver.maskinporten | ||
|
||
import com.nimbusds.jose.JOSEObjectType | ||
import com.nimbusds.jose.JWSAlgorithm | ||
import com.nimbusds.jose.JWSHeader | ||
import com.nimbusds.jose.crypto.RSASSASigner | ||
import com.nimbusds.jose.jwk.RSAKey | ||
import com.nimbusds.jwt.JWTClaimsSet | ||
import com.nimbusds.jwt.SignedJWT | ||
import java.util.Date | ||
import java.util.UUID | ||
|
||
class MaskinportenClientConfigJwk( | ||
override val scope: String, | ||
override val clientId: String, | ||
override val issuer: String, | ||
override val endpoint: String, | ||
val clientJwk: String, | ||
override val additionalClaims: Map<String, Any>? = null | ||
) : MaskinportenClientConfig { | ||
|
||
private val rsaKey: RSAKey by lazy { | ||
try { | ||
RSAKey.parse(clientJwk) | ||
} catch (e: Exception) { | ||
throw IllegalArgumentException("Invalid JWK format", e) | ||
} | ||
} | ||
private val signer: RSASSASigner by lazy { | ||
RSASSASigner(rsaKey.toPrivateKey()) | ||
} | ||
private val header: JWSHeader by lazy { | ||
JWSHeader.Builder(JWSAlgorithm.RS256) | ||
.keyID(rsaKey.keyID) | ||
.type(JOSEObjectType.JWT) | ||
.build() | ||
} | ||
|
||
private fun claims(): JWTClaimsSet { | ||
val now = currentTime() | ||
val builder = JWTClaimsSet.Builder() | ||
.issuer(clientId) | ||
.audience(issuer) | ||
.issueTime(now) | ||
.claim("scope", scope) | ||
.expirationTime(Date.from(now.toInstant().plusSeconds(60))) | ||
.jwtID(UUID.randomUUID().toString()) | ||
|
||
additionalClaims?.forEach { (key, value) -> | ||
builder.claim(key, value) | ||
} | ||
|
||
return builder.build() | ||
} | ||
|
||
override fun getJwtAssertion(): String { | ||
return SignedJWT(header, claims()).apply { sign(signer) }.serialize() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package no.nav.helsearbeidsgiver.maskinporten | ||
|
||
import com.nimbusds.jose.JOSEObjectType | ||
import com.nimbusds.jose.JWSAlgorithm | ||
import com.nimbusds.jose.JWSHeader | ||
import com.nimbusds.jose.crypto.RSASSASigner | ||
import com.nimbusds.jwt.JWTClaimsSet | ||
import com.nimbusds.jwt.SignedJWT | ||
import java.security.KeyFactory | ||
import java.security.PrivateKey | ||
import java.security.spec.PKCS8EncodedKeySpec | ||
import java.util.Base64 | ||
import java.util.Date | ||
import java.util.UUID | ||
|
||
/** | ||
* MaskinportenClientConfigPkey er en implementasjon av MaskinportenClientConfig med privatekey som autentiseringsmetode for maskinporten | ||
* | ||
* @param kid Det er id-en til Nøkkelen key-id (kid) | ||
* @param privateKey Det er privatekey som skal brukes til å signere JWT tokenet | ||
* @param clientId issuer - Din egen client_id. | ||
* @param issuer Audience - issuer-identifikatoren til Maskinporten. Verdi for aktuelt miljø finner du på .well-known-endpunkt. | ||
* @param consumerOrgNr Det er organisasjonsnummeret til virksomheten som skal bruke maskinporten på vegne av | ||
* @param scope Space-separert liste over scopes som klienten forespør. | ||
* @param endpoint Det er endepunktet til maskinporten | ||
* | ||
*/ | ||
class MaskinportenClientConfigPkey( | ||
val kid: String, | ||
val privateKey: String, | ||
override val clientId: String, | ||
override val issuer: String, | ||
override val scope: String, | ||
override val endpoint: String, | ||
override val additionalClaims: Map<String, Any>? = null | ||
) : MaskinportenClientConfig { | ||
|
||
val currentTimestamp = System.currentTimeMillis() / 1000 | ||
override fun getJwtAssertion(): String { | ||
val header = | ||
JWSHeader | ||
.Builder(JWSAlgorithm.RS256) | ||
.keyID(kid) | ||
.type(JOSEObjectType.JWT) | ||
.build() | ||
|
||
val signer = RSASSASigner(loadPrivateKey(privateKey)) | ||
val signedJWT = SignedJWT(header, claims()) | ||
signedJWT.sign(signer) | ||
|
||
return signedJWT.serialize() | ||
} | ||
|
||
private fun claims(): JWTClaimsSet { | ||
val now = currentTime() | ||
val builder = JWTClaimsSet | ||
.Builder() | ||
.issuer(clientId) | ||
.audience(issuer) | ||
.issueTime(now) | ||
.expirationTime(Date.from(now.toInstant().plusSeconds(60))) | ||
.claim("scope", scope) | ||
.jwtID(UUID.randomUUID().toString()) | ||
|
||
additionalClaims?.forEach { (key, value) -> | ||
builder.claim(key, value) | ||
} | ||
|
||
return builder.build() | ||
} | ||
} | ||
|
||
private fun loadPrivateKey(key: String): PrivateKey { | ||
val keyText = | ||
key | ||
.replace("-----BEGIN PRIVATE KEY-----", "") | ||
.replace("-----END PRIVATE KEY-----", "") | ||
.replace("\n", "") | ||
.replace("\\s".toRegex(), "") | ||
|
||
val encoded = Base64.getDecoder().decode(keyText) | ||
return KeyFactory | ||
.getInstance("RSA") | ||
.generatePrivate(PKCS8EncodedKeySpec(encoded)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters