Skip to content

Commit

Permalink
test: configure mock server with preset signing key
Browse files Browse the repository at this point in the history
Also add some tests that depend on said key.

Co-authored-by: Tommy Trøen <[email protected]>
  • Loading branch information
tronghn and tommytroen committed Nov 8, 2024
1 parent 9cc7b9e commit 104ffda
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 100 deletions.
10 changes: 10 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,13 @@ services:
image: ghcr.io/navikt/mock-oauth2-server:2.1.10
ports:
- "8080:8080"
environment:
JSON_CONFIG: |
{
"tokenProvider" : {
"keyProvider" : {
"initialKeys" : "{\"p\":\"_LNnIjBshCrFuxtjUC2KKzg_NTVv26UZh5j12_9r5mYTxb8yW047jOYFEGvIdMkTRLGOBig6fLWzgd62lnLainzV35J6K6zr4jQfTldLondlkldMR6nQrp1KfnNUuRbKvzpNKkhl12-f1l91l0tCx3s4blztvWgdzN2xBfvWV68\",\"kty\":\"RSA\",\"q\":\"9MIWsbIA3WjiR_Ful5FM8NCgb6JdS2D6ySHVepoNI-iAPilcltF_J2orjfLqAxeztTskPi45wtF_-eV4GIYSzvMo-gFiXLMrvEa7WaWizMi_7Bu9tEk3m_f3IDLN9lwULYoebkDbiXx6GOiuj0VkuKz8ckYFNKLCMP9QRLFff-0\",\"d\":\"J6UX848X8tNz-09PFvcFDUVqak32GXzoPjnuDjBsxNUvG7LxenLmM_i8tvYl0EW9Ztn4AiCqJUoHw5cX3jz_mSqGl7ciaDedpKm_AetcZwHiEuT1EpSKRPMmOMQSqcJqXrdbbWB8gdUrnTKZIlJCfj7yqgT16ypC43TnwjA0UwxhG5pHaYjKI3pPdoHg2BzA-iubHjVn15Sz7-pnjBmeGDbEFa7ADY-1yPHCmqqvPKTNhoCNW6RpG34Id9hXslPa3X-7pAhJrDBd0_NPlktSA2rUkifYiZURhHR5ijhe0v3uw6kYP8f_foVm_C8O1ExkxXh9Dg8KDZ89dbsSOtBc0Q\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"l7C_WJgbZ_6e59vPrFETAehX7Dsp7fIyvSV4XhotsGs\",\"qi\":\"cQFN5q5WhYkzgd1RS0rGqvpX1AkmZMrLv2MW04gSfu0dDwpbsSAu8EUCQW9oA4pr6V7R9CBSu9kdN2iY5SR-hZvEad5nDKPV1F3TMQYv5KpRiS_0XhfV5PcolUJVO_4p3h8d-mo2hh1Sw2fairAKOzvnwJCQ6DFkiY7H1cqwA54\",\"dp\":\"YTql9AGtvyy158gh7jeXcgmySEbHQzvDFulDr-IXIg8kjHGEbp0rTIs0Z50RA95aC5RFkRjpaBKBfvaySjDm5WIi6GLzntpp6B8l7H6qG1jVO_la4Df2kzjx8LVvY8fhOrKz_hDdHodUeKdCF3RdvWMr00ruLnJhBPJHqoW7cwE\",\"alg\":\"RS256\",\"dq\":\"IZA4AngRbEtEtG7kJn6zWVaSmZxfRMXwvgIYvy4-3Qy2AVA0tS3XTPVfMaD8_B2U9CY_CxPVseR-sysHc_12uNBZbycfcOzU84WTjXCMSZ7BysPnGMDtkkLHra-p1L29upz1HVNhh5H9QEswHM98R2LZX2ZAsn4bORLZ1AGqweU\",\"n\":\"8ZqUp5Cs90XpNn8tJBdUUxdGH4bjqKjFj8lyB3x50RpTuECuwzX1NpVqyFENDiEtMja5fdmJl6SErjnhj6kbhcmfmFibANuG-0WlV5yMysdSbocd75C1JQbiPdpHdXrijmVFMfDnoZTQ-ErNsqqngTNkn5SXBcPenli6Cf9MTSchZuh_qFj_B7Fp3CWKehTiyBcLlNOIjYsXX8WQjZkWKGpQ23AWjZulngWRektLcRWuEKTWaRBtbAr3XAfSmcqTICrebaD3IMWKHDtvzHAt_pt4wnZ06clgeO2Wbc980usnpsF7g8k9p81RcbS4JEZmuuA9NCmOmbyADXwgA9_-Aw\"}",
"algorithm" : "RS256"
}
}
}
228 changes: 129 additions & 99 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ mod tests {
use crate::app::App;
use crate::config::Config;
use crate::identity_provider::{ErrorResponse, IdentityProvider, IntrospectRequest, IntrospectResponse, OAuthErrorCode, TokenExchangeRequest, TokenRequest, TokenResponse};
use axum::routing::get;
use axum::{Json, Router};
use jsonwebkey as jwk;
use jsonwebtoken as jwt;
use log::{info, LevelFilter};
Expand All @@ -81,6 +79,7 @@ mod tests {
use std::collections::HashMap;
use std::fmt::Debug;
use testcontainers::{ContainerAsync, GenericImage};
use crate::claims::epoch_now_secs;

/// Test a full round-trip of the `/token`, `/token/exchange`, and `/introspect` endpoints.
///
Expand All @@ -101,6 +100,7 @@ mod tests {
let join_handler = tokio::spawn(async move {
testapp.app.run().await.unwrap();
});
let identity_provider_address = format!("{}:{}", testapp.docker.host.clone(), testapp.docker.port);

for format in [RequestFormat::Form, RequestFormat::Json] {
machine_to_machine_token(
Expand All @@ -123,7 +123,7 @@ mod tests {
testapp.cfg.azure_ad_issuer.clone(),
testapp.cfg.azure_ad_client_id.clone(),
address.to_string(),
format!("{}:{}", testapp.docker.host.clone(), testapp.docker.port),
identity_provider_address.to_string(),
IdentityProvider::AzureAD,
format.clone(),
).await;
Expand All @@ -132,7 +132,7 @@ mod tests {
testapp.cfg.token_x_issuer.clone(),
testapp.cfg.token_x_client_id.clone(),
address.to_string(),
format!("{}:{}", testapp.docker.host.clone(), testapp.docker.port),
identity_provider_address.to_string(),
IdentityProvider::TokenX,
format,
).await;
Expand All @@ -144,9 +144,13 @@ mod tests {
test_introspect_token_is_not_a_jwt(&address).await;
test_introspect_token_missing_issuer(&address).await;
test_introspect_token_unrecognized_issuer(&address).await;
test_introspect_token_missing_kid(&address).await;
test_introspect_token_missing_key_in_jwks(&address).await;
test_introspect_token_invalid_timestamps(&address).await;
test_introspect_token_missing_kid(&address, &identity_provider_address).await;
test_introspect_token_missing_key_in_jwks(&address, &identity_provider_address).await;
test_introspect_token_is_expired(&address, &identity_provider_address).await;

// FIXME: these tests don't fail as expected; validation crate not working?
//test_introspect_token_is_issued_in_the_future(&address, &identity_provider_address).await;
//test_introspect_token_has_not_before_in_the_future(&address, &identity_provider_address).await;

// TODO: implement these tests:
// * /token
Expand Down Expand Up @@ -181,7 +185,7 @@ mod tests {
}

async fn test_introspect_token_unrecognized_issuer(address: &str) {
let token = TokenServer::token(
let token = Token::sign(
TokenClaims::from([
("iss".into(), Value::String("snafu".into())),
])
Expand All @@ -197,7 +201,7 @@ mod tests {
}

async fn test_introspect_token_missing_issuer(address: &str) {
let token = TokenServer::token(TokenClaims::new());
let token = Token::sign(TokenClaims::new());
test_well_formed_json_request(
&format!("http://{}/api/v1/introspect", address),
IntrospectRequest {
Expand All @@ -219,10 +223,10 @@ mod tests {
).await;
}

async fn test_introspect_token_missing_kid(address: &str) {
let token = TokenServer::token(
async fn test_introspect_token_missing_kid(address: &str, identity_provider_address: &str) {
let token = Token::sign(
TokenClaims::from([
("iss".into(), Value::String("http://localhost:8080/maskinporten".into())),
("iss".into(), format!("http://{}/maskinporten", identity_provider_address).into()),
])
);
test_well_formed_json_request(
Expand All @@ -235,10 +239,10 @@ mod tests {
).await;
}

async fn test_introspect_token_missing_key_in_jwks(address: &str) {
let token = TokenServer::token_with_kid(
async fn test_introspect_token_missing_key_in_jwks(address: &str, identity_provider_address: &str) {
let token = Token::sign_with_kid(
TokenClaims::from([
("iss".into(), Value::String("http://localhost:8080/maskinporten".into())),
("iss".into(), format!("http://{}/maskinporten", identity_provider_address).into()),
]),
"missing-key",
);
Expand All @@ -252,97 +256,72 @@ mod tests {
StatusCode::OK,
).await;
}
// * [ ] invalid or expired timestamps in nbf, iat, exp
async fn test_introspect_token_invalid_timestamps(address: &str) {

}

async fn yolo() {
let server = TokenServer::new().await;
let address = server.address();
let join_handler = tokio::spawn(async move {
server.run().await.unwrap();
});

// Set up Texas
//let cfg = Config::mock(address, server.port());
//let app = App::new(cfg.clone()).await;


let client = reqwest::Client::new();
let response = client.get(format!("http://{}/jwks", address)).send().await.unwrap();
println!("{:?}", response.text().await.unwrap());
join_handler.abort();
}

struct TokenServer {
listener: tokio::net::TcpListener,
keys: HashMap<String, Vec<jwk::JsonWebKey>>,
}

type TokenClaims = HashMap<String, Value>;
async fn test_introspect_token_is_expired(address: &str, identity_provider_address: &str) {
// token is expired
let token = Token::sign_with_kid(
TokenClaims::from([
("iss".into(), format!("http://{}/maskinporten", identity_provider_address).into()),
("nbf".into(), (epoch_now_secs()).into()),
("iat".into(), (epoch_now_secs()).into()),
("exp".into(), (epoch_now_secs() - 120).into()),
]),
"maskinporten",
);

struct Token {
header: jwt::Header,
claims: TokenClaims,
test_well_formed_json_request(
&format!("http://{}/api/v1/introspect", address),
IntrospectRequest {
token,
},
IntrospectResponse::new_invalid("invalid token: ExpiredSignature"),
StatusCode::OK,
).await;
}

impl Token {
fn new(claims: TokenClaims) -> Self {
Self {
header: jwt::Header::new(jwt::Algorithm::RS256),
claims,
}
}
// FIXME: this test doesn't fail as expected; validation crate not working?
async fn test_introspect_token_is_issued_in_the_future(address: &str, identity_provider_address: &str) {
let token = Token::sign_with_kid(
TokenClaims::from([
("iss".into(), format!("http://{}/maskinporten", identity_provider_address).into()),
("nbf".into(), (epoch_now_secs()).into()),
("iat".into(), (epoch_now_secs() + 120).into()),
("exp".into(), (epoch_now_secs() + 300).into()),
]),
"maskinporten",
);

fn sign(self, key: &jwk::JsonWebKey) -> String {
jwt::encode(
&self.header,
&self.claims,
&key.key.to_encoding_key(),
).unwrap()
}
test_well_formed_json_request(
&format!("http://{}/api/v1/introspect", address),
IntrospectRequest {
token,
},
IntrospectResponse::new_invalid("token is issued in the future"),
StatusCode::OK,
).await;
}

impl TokenServer {
const SIGNING_KEY: &'static str = r#"{"p":"_LNnIjBshCrFuxtjUC2KKzg_NTVv26UZh5j12_9r5mYTxb8yW047jOYFEGvIdMkTRLGOBig6fLWzgd62lnLainzV35J6K6zr4jQfTldLondlkldMR6nQrp1KfnNUuRbKvzpNKkhl12-f1l91l0tCx3s4blztvWgdzN2xBfvWV68","kty":"RSA","q":"9MIWsbIA3WjiR_Ful5FM8NCgb6JdS2D6ySHVepoNI-iAPilcltF_J2orjfLqAxeztTskPi45wtF_-eV4GIYSzvMo-gFiXLMrvEa7WaWizMi_7Bu9tEk3m_f3IDLN9lwULYoebkDbiXx6GOiuj0VkuKz8ckYFNKLCMP9QRLFff-0","d":"J6UX848X8tNz-09PFvcFDUVqak32GXzoPjnuDjBsxNUvG7LxenLmM_i8tvYl0EW9Ztn4AiCqJUoHw5cX3jz_mSqGl7ciaDedpKm_AetcZwHiEuT1EpSKRPMmOMQSqcJqXrdbbWB8gdUrnTKZIlJCfj7yqgT16ypC43TnwjA0UwxhG5pHaYjKI3pPdoHg2BzA-iubHjVn15Sz7-pnjBmeGDbEFa7ADY-1yPHCmqqvPKTNhoCNW6RpG34Id9hXslPa3X-7pAhJrDBd0_NPlktSA2rUkifYiZURhHR5ijhe0v3uw6kYP8f_foVm_C8O1ExkxXh9Dg8KDZ89dbsSOtBc0Q","e":"AQAB","use":"sig","kid":"l7C_WJgbZ_6e59vPrFETAehX7Dsp7fIyvSV4XhotsGs","qi":"cQFN5q5WhYkzgd1RS0rGqvpX1AkmZMrLv2MW04gSfu0dDwpbsSAu8EUCQW9oA4pr6V7R9CBSu9kdN2iY5SR-hZvEad5nDKPV1F3TMQYv5KpRiS_0XhfV5PcolUJVO_4p3h8d-mo2hh1Sw2fairAKOzvnwJCQ6DFkiY7H1cqwA54","dp":"YTql9AGtvyy158gh7jeXcgmySEbHQzvDFulDr-IXIg8kjHGEbp0rTIs0Z50RA95aC5RFkRjpaBKBfvaySjDm5WIi6GLzntpp6B8l7H6qG1jVO_la4Df2kzjx8LVvY8fhOrKz_hDdHodUeKdCF3RdvWMr00ruLnJhBPJHqoW7cwE","alg":"RS256","dq":"IZA4AngRbEtEtG7kJn6zWVaSmZxfRMXwvgIYvy4-3Qy2AVA0tS3XTPVfMaD8_B2U9CY_CxPVseR-sysHc_12uNBZbycfcOzU84WTjXCMSZ7BysPnGMDtkkLHra-p1L29upz1HVNhh5H9QEswHM98R2LZX2ZAsn4bORLZ1AGqweU","n":"8ZqUp5Cs90XpNn8tJBdUUxdGH4bjqKjFj8lyB3x50RpTuECuwzX1NpVqyFENDiEtMja5fdmJl6SErjnhj6kbhcmfmFibANuG-0WlV5yMysdSbocd75C1JQbiPdpHdXrijmVFMfDnoZTQ-ErNsqqngTNkn5SXBcPenli6Cf9MTSchZuh_qFj_B7Fp3CWKehTiyBcLlNOIjYsXX8WQjZkWKGpQ23AWjZulngWRektLcRWuEKTWaRBtbAr3XAfSmcqTICrebaD3IMWKHDtvzHAt_pt4wnZ06clgeO2Wbc980usnpsF7g8k9p81RcbS4JEZmuuA9NCmOmbyADXwgA9_-Aw"}"#;
async fn new() -> Self {
let mut keys = HashMap::<String, Vec<jwk::JsonWebKey>>::new();
keys.insert("keys".to_string(), vec![Self::get_signing_key()]);
Self {
listener: tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(),
keys,
}
}

fn port(&self) -> u16 {
self.listener.local_addr().unwrap().port()
}

fn address(&self) -> String {
self.listener.local_addr().unwrap().to_string()
}

fn token(claims: TokenClaims) -> String {
Token::new(claims).sign(&Self::get_signing_key())
}

fn token_with_kid(claims: TokenClaims, kid: &str) -> String {
let mut token = Token::new(claims);
token.header.kid = Some(kid.to_string());
token.sign(&Self::get_signing_key())
}

pub async fn run(self) -> std::io::Result<()> {
let app = Router::new()
.route("/jwks", get(|| async { Json(self.keys) }));

axum::serve(self.listener, app).await
}
// FIXME: this test doesn't fail as expected; validation crate not working?
async fn test_introspect_token_has_not_before_in_the_future(address: &str, identity_provider_address: &str) {
let token = Token::sign_with_kid(
TokenClaims::from([
("iss".into(), format!("http://{}/maskinporten", identity_provider_address).into()),
("nbf".into(), (epoch_now_secs() - 120).into()),
("iat".into(), (epoch_now_secs()).into()),
("exp".into(), (epoch_now_secs() + 300).into()),
]),
"maskinporten",
);
println!("{}", token);

fn get_signing_key() -> jwk::JsonWebKey {
Self::SIGNING_KEY.parse().unwrap()
}
test_well_formed_json_request(
&format!("http://{}/api/v1/introspect", address),
IntrospectRequest {
token,
},
IntrospectResponse::new_invalid("token has not before in the future"),
StatusCode::OK,
).await;
}

async fn test_token_exchange_missing_or_empty_user_token(address: &str) {
Expand Down Expand Up @@ -539,25 +518,76 @@ mod tests {
}
}

type TokenClaims = HashMap<String, Value>;

struct Token {
header: jwt::Header,
claims: TokenClaims,
}

impl Token {
const SIGNING_KEY: &'static str = r#"{"p":"_LNnIjBshCrFuxtjUC2KKzg_NTVv26UZh5j12_9r5mYTxb8yW047jOYFEGvIdMkTRLGOBig6fLWzgd62lnLainzV35J6K6zr4jQfTldLondlkldMR6nQrp1KfnNUuRbKvzpNKkhl12-f1l91l0tCx3s4blztvWgdzN2xBfvWV68","kty":"RSA","q":"9MIWsbIA3WjiR_Ful5FM8NCgb6JdS2D6ySHVepoNI-iAPilcltF_J2orjfLqAxeztTskPi45wtF_-eV4GIYSzvMo-gFiXLMrvEa7WaWizMi_7Bu9tEk3m_f3IDLN9lwULYoebkDbiXx6GOiuj0VkuKz8ckYFNKLCMP9QRLFff-0","d":"J6UX848X8tNz-09PFvcFDUVqak32GXzoPjnuDjBsxNUvG7LxenLmM_i8tvYl0EW9Ztn4AiCqJUoHw5cX3jz_mSqGl7ciaDedpKm_AetcZwHiEuT1EpSKRPMmOMQSqcJqXrdbbWB8gdUrnTKZIlJCfj7yqgT16ypC43TnwjA0UwxhG5pHaYjKI3pPdoHg2BzA-iubHjVn15Sz7-pnjBmeGDbEFa7ADY-1yPHCmqqvPKTNhoCNW6RpG34Id9hXslPa3X-7pAhJrDBd0_NPlktSA2rUkifYiZURhHR5ijhe0v3uw6kYP8f_foVm_C8O1ExkxXh9Dg8KDZ89dbsSOtBc0Q","e":"AQAB","use":"sig","kid":"l7C_WJgbZ_6e59vPrFETAehX7Dsp7fIyvSV4XhotsGs","qi":"cQFN5q5WhYkzgd1RS0rGqvpX1AkmZMrLv2MW04gSfu0dDwpbsSAu8EUCQW9oA4pr6V7R9CBSu9kdN2iY5SR-hZvEad5nDKPV1F3TMQYv5KpRiS_0XhfV5PcolUJVO_4p3h8d-mo2hh1Sw2fairAKOzvnwJCQ6DFkiY7H1cqwA54","dp":"YTql9AGtvyy158gh7jeXcgmySEbHQzvDFulDr-IXIg8kjHGEbp0rTIs0Z50RA95aC5RFkRjpaBKBfvaySjDm5WIi6GLzntpp6B8l7H6qG1jVO_la4Df2kzjx8LVvY8fhOrKz_hDdHodUeKdCF3RdvWMr00ruLnJhBPJHqoW7cwE","alg":"RS256","dq":"IZA4AngRbEtEtG7kJn6zWVaSmZxfRMXwvgIYvy4-3Qy2AVA0tS3XTPVfMaD8_B2U9CY_CxPVseR-sysHc_12uNBZbycfcOzU84WTjXCMSZ7BysPnGMDtkkLHra-p1L29upz1HVNhh5H9QEswHM98R2LZX2ZAsn4bORLZ1AGqweU","n":"8ZqUp5Cs90XpNn8tJBdUUxdGH4bjqKjFj8lyB3x50RpTuECuwzX1NpVqyFENDiEtMja5fdmJl6SErjnhj6kbhcmfmFibANuG-0WlV5yMysdSbocd75C1JQbiPdpHdXrijmVFMfDnoZTQ-ErNsqqngTNkn5SXBcPenli6Cf9MTSchZuh_qFj_B7Fp3CWKehTiyBcLlNOIjYsXX8WQjZkWKGpQ23AWjZulngWRektLcRWuEKTWaRBtbAr3XAfSmcqTICrebaD3IMWKHDtvzHAt_pt4wnZ06clgeO2Wbc980usnpsF7g8k9p81RcbS4JEZmuuA9NCmOmbyADXwgA9_-Aw"}"#;

fn new(claims: TokenClaims) -> Self {
Self {
header: jwt::Header::new(jwt::Algorithm::RS256),
claims,
}
}

fn sign(claims: TokenClaims) -> String {
Self::new(claims).encode()
}

fn sign_with_kid(claims: TokenClaims, kid: &str) -> String {
let mut token = Self::new(claims);
token.header.kid = Some(kid.to_string());
token.encode()
}

fn encode(&self) -> String {
let key = Self::get_signing_key();
jwt::encode(
&self.header,
&self.claims,
&key.key.to_encoding_key(),
).unwrap()
}

fn get_signing_key() -> jwk::JsonWebKey {
Self::SIGNING_KEY.parse().unwrap()
}
}

struct DockerRuntimeParams {
container: Option<ContainerAsync<GenericImage>>,
host: String,
port: u16,
}

impl DockerRuntimeParams {
const MOCK_OAUTH_SERVER_JSON_CONFIG: &'static str = r#"{
"tokenProvider" : {
"keyProvider" : {
"initialKeys" : "{\"p\":\"_LNnIjBshCrFuxtjUC2KKzg_NTVv26UZh5j12_9r5mYTxb8yW047jOYFEGvIdMkTRLGOBig6fLWzgd62lnLainzV35J6K6zr4jQfTldLondlkldMR6nQrp1KfnNUuRbKvzpNKkhl12-f1l91l0tCx3s4blztvWgdzN2xBfvWV68\",\"kty\":\"RSA\",\"q\":\"9MIWsbIA3WjiR_Ful5FM8NCgb6JdS2D6ySHVepoNI-iAPilcltF_J2orjfLqAxeztTskPi45wtF_-eV4GIYSzvMo-gFiXLMrvEa7WaWizMi_7Bu9tEk3m_f3IDLN9lwULYoebkDbiXx6GOiuj0VkuKz8ckYFNKLCMP9QRLFff-0\",\"d\":\"J6UX848X8tNz-09PFvcFDUVqak32GXzoPjnuDjBsxNUvG7LxenLmM_i8tvYl0EW9Ztn4AiCqJUoHw5cX3jz_mSqGl7ciaDedpKm_AetcZwHiEuT1EpSKRPMmOMQSqcJqXrdbbWB8gdUrnTKZIlJCfj7yqgT16ypC43TnwjA0UwxhG5pHaYjKI3pPdoHg2BzA-iubHjVn15Sz7-pnjBmeGDbEFa7ADY-1yPHCmqqvPKTNhoCNW6RpG34Id9hXslPa3X-7pAhJrDBd0_NPlktSA2rUkifYiZURhHR5ijhe0v3uw6kYP8f_foVm_C8O1ExkxXh9Dg8KDZ89dbsSOtBc0Q\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"l7C_WJgbZ_6e59vPrFETAehX7Dsp7fIyvSV4XhotsGs\",\"qi\":\"cQFN5q5WhYkzgd1RS0rGqvpX1AkmZMrLv2MW04gSfu0dDwpbsSAu8EUCQW9oA4pr6V7R9CBSu9kdN2iY5SR-hZvEad5nDKPV1F3TMQYv5KpRiS_0XhfV5PcolUJVO_4p3h8d-mo2hh1Sw2fairAKOzvnwJCQ6DFkiY7H1cqwA54\",\"dp\":\"YTql9AGtvyy158gh7jeXcgmySEbHQzvDFulDr-IXIg8kjHGEbp0rTIs0Z50RA95aC5RFkRjpaBKBfvaySjDm5WIi6GLzntpp6B8l7H6qG1jVO_la4Df2kzjx8LVvY8fhOrKz_hDdHodUeKdCF3RdvWMr00ruLnJhBPJHqoW7cwE\",\"alg\":\"RS256\",\"dq\":\"IZA4AngRbEtEtG7kJn6zWVaSmZxfRMXwvgIYvy4-3Qy2AVA0tS3XTPVfMaD8_B2U9CY_CxPVseR-sysHc_12uNBZbycfcOzU84WTjXCMSZ7BysPnGMDtkkLHra-p1L29upz1HVNhh5H9QEswHM98R2LZX2ZAsn4bORLZ1AGqweU\",\"n\":\"8ZqUp5Cs90XpNn8tJBdUUxdGH4bjqKjFj8lyB3x50RpTuECuwzX1NpVqyFENDiEtMja5fdmJl6SErjnhj6kbhcmfmFibANuG-0WlV5yMysdSbocd75C1JQbiPdpHdXrijmVFMfDnoZTQ-ErNsqqngTNkn5SXBcPenli6Cf9MTSchZuh_qFj_B7Fp3CWKehTiyBcLlNOIjYsXX8WQjZkWKGpQ23AWjZulngWRektLcRWuEKTWaRBtbAr3XAfSmcqTICrebaD3IMWKHDtvzHAt_pt4wnZ06clgeO2Wbc980usnpsF7g8k9p81RcbS4JEZmuuA9NCmOmbyADXwgA9_-Aw\"}",
"algorithm" : "RS256"
}
}
}"#;

/// Runs Docker from Rust, no external setup needed
#[cfg(feature = "docker")]
async fn init() -> DockerRuntimeParams {
use reqwest::StatusCode;
use testcontainers::core::wait::HttpWaitStrategy;
use testcontainers::core::{IntoContainerPort, WaitFor};
use testcontainers::core::{IntoContainerPort, WaitFor, ImageExt};
use testcontainers::runners::AsyncRunner;

// Set up Docker container
let container = GenericImage::new("ghcr.io/navikt/mock-oauth2-server", "2.1.10")
.with_exposed_port(8080.tcp())
.with_wait_for(WaitFor::Http(HttpWaitStrategy::new("/maskinporten/.well-known/openid-configuration").with_expected_status_code(StatusCode::OK)))
.with_env_var("JSON_CONFIG", Self::MOCK_OAUTH_SERVER_JSON_CONFIG)
.start()
.await
.unwrap();
Expand Down
Loading

0 comments on commit 104ffda

Please sign in to comment.