Servidor mock local

keenauth mock serve ejecuta en su máquina un pequeño servidor de OpenID Connect, SAML 2.0 y SCIM 2.0, y una versión en memoria de la API de gestión /v1, para trabajos de CI sin acceso a la red y para el desarrollo local. No necesita un entorno de KeenAuth, ninguna clave de API ni Internet. Todos los datos viven en memoria y se eliminan cuando el proceso termina.

El servidor mock no es KeenAuth. Implementa solo los flujos que se indican abajo, aprueba automáticamente cada solicitud y comprueba bastante menos que el servicio real. Su entorno development alojado es la única referencia para el comportamiento real: ejecute sus pruebas de extremo a extremo contra él antes de publicar.

Iniciar el servidor

keenauth mock serve

De forma predeterminada, el servidor escucha en 127.0.0.1:4010, una dirección de bucle local a la que otras máquinas no pueden acceder. --port cambia el puerto (0 elige uno libre). --host cambia la dirección; cualquier dirección que no sea de bucle local expone el servidor mock a su red, y la CLI muestra una advertencia. Detenga el servidor con Ctrl+C.

El comando no lee credenciales y no envía nada a KeenAuth.

Endpoints

Ruta Función
/.well-known/openid-configuration Documento de descubrimiento OIDC (también servido en /.well-known/oauth-authorization-server)
/.well-known/jwks.json Conjunto de claves públicas de prueba (ID de clave keenauth-test-1)
/oauth2/authorize Endpoint de autorización: flujo de código de autorización con PKCE (S256)
/oauth2/token Endpoint de token: concesiones authorization_code y refresh_token
/oauth2/userinfo Endpoint UserInfo (token de acceso Bearer con el scope openid)
/saml-idp/<application_id>/metadata Metadatos del proveedor de identidad SAML 2.0
/saml-idp/<application_id>/sso Endpoint de inicio de sesión único SAML (bindings HTTP-Redirect y HTTP-POST)
/scim/v2/<directory_id>/… Endpoints SCIM 2.0: Users, Groups, ServiceProviderConfig, ResourceTypes, Schemas
/v1/… API de gestión en memoria: cada operación del documento OpenAPI de la API de gestión

Las URL de los endpoints del documento de descubrimiento y de los metadatos SAML apuntan a la dirección local en la que escucha el servidor. <application_id> y <directory_id> son nombres que usted elige (de 1 a 64 caracteres de A-Z, a-z, 0-9, -, _); no hace falta registrar nada antes.

Cómo se comporta

Tokens y su verificador

Los tokens se firman con la clave pública de prueba del kit de pruebas sin conexión y llevan el emisor https://test.keenauth.invalid, no la dirección local. El dominio de primer nivel .invalid está reservado, así que un verificador de producción nunca puede aceptar estos tokens: los verificadores del SDK solo los aceptan en modo de prueba, que usted activa explícitamente en el código de prueba.

// Go: accept tokens from the mock server in a test.
v, err := keenauthtest.NewVerifier(verify.Config{Audience: "https://test.keenauth.invalid/oauth2/userinfo"})
if err != nil {
	t.Fatal(err)
}
claims, err := v.VerifyAccessToken(ctx, accessToken, nil)

Use el mismo modo de prueba en TypeScript (createTestVerifier) y en Python (keenauth.testing.verifier). Las bibliotecas genéricas de cliente OIDC que exigen que el issuer del documento de descubrimiento sea igual a la URL desde la que se obtuvo rechazarán el documento del servidor mock; configúrelas con las URL de los endpoints directamente, o pruébelas contra su entorno development.

Ejemplo: el flujo completo con curl

El ejemplo necesita curl, openssl y jq. Inicie primero el servidor en otra terminal.

BASE=http://127.0.0.1:4010
REDIRECT=http://127.0.0.1:8080/callback
VERIFIER=$(openssl rand -hex 32)
CHALLENGE=$(printf '%s' "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')

# 1. Authorize: the server answers with a redirect that carries the code.
LOCATION=$(curl -s -o /dev/null -w '%{redirect_url}' --get "$BASE/oauth2/authorize" \
  --data-urlencode response_type=code --data-urlencode client_id=app_local \
  --data-urlencode redirect_uri="$REDIRECT" --data-urlencode 'scope=openid email offline_access' \
  --data-urlencode state=xyz --data-urlencode code_challenge="$CHALLENGE" \
  --data-urlencode code_challenge_method=S256)
CODE=$(printf '%s' "$LOCATION" | sed -E 's/.*[?&]code=([^&]+).*/\1/')

# 2. Exchange the code for tokens.
TOKENS=$(curl -s "$BASE/oauth2/token" -d grant_type=authorization_code -d client_id=app_local \
  --data-urlencode code="$CODE" --data-urlencode redirect_uri="$REDIRECT" -d code_verifier="$VERIFIER")

# 3. Call UserInfo with the access token.
curl -s "$BASE/oauth2/userinfo" -H "Authorization: Bearer $(printf '%s' "$TOKENS" | jq -r .access_token)"

# 4. Refresh.
curl -s "$BASE/oauth2/token" -d grant_type=refresh_token -d client_id=app_local \
  --data-urlencode refresh_token="$(printf '%s' "$TOKENS" | jq -r .refresh_token)"

El paso 3 muestra el usuario de prueba:

{"email":"test.user@example.test","email_verified":true,"sub":"usr_01m3vnbwg0e8mbe7h7xxp6rmkc"}

Proveedor de identidad SAML

Use el servidor mock como proveedor de identidad de un proveedor de servicios SAML que esté desarrollando: apunte el proveedor de servicios a la URL de metadatos, inicie sesión y el servidor mock responderá con una respuesta firmada para el usuario de prueba. Las rutas siguen al proveedor de identidad SAML alojado que KeenAuth planea para una versión posterior.

La clave de firma es pública. Se deriva de una etiqueta publicada, así que cualquiera puede firmar respuestas que este certificado verifica. Su huella SHA-256 es fcc2fc37b9ddb800721283156f9eb26ff1b80f099d996a65650f8cb469a9be81 y su subject dice TEST ONLY. Regístrela solo en configuraciones de desarrollo y prueba de su proveedor de servicios, nunca en producción. KeenAuth lo aplica a sus propias conexiones SAML: en entornos de staging y producción rechaza esta clave y cualquier ID de entidad bajo .invalid, al importar metadatos o añadir un certificado, y de nuevo al iniciar sesión; los entornos de desarrollo las aceptan.

Ejemplo: un inicio de sesión SAML con curl

El ejemplo necesita curl y openssl. Inicie primero el servidor en otra terminal.

BASE=http://127.0.0.1:4010
APP=app_local
ACS=http://127.0.0.1:8080/saml/acs

# 1. IdP metadata: entity ID, signing certificate and SSO URL for your service provider.
curl -s "$BASE/saml-idp/$APP/metadata" -o idp-metadata.xml

# 2. Send an AuthnRequest with the HTTP-POST binding (base64, no compression).
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
REQUEST=$(printf '<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_req1" Version="2.0" IssueInstant="%s" AssertionConsumerServiceURL="%s"><saml:Issuer>https://sp.example.com</saml:Issuer></samlp:AuthnRequest>' "$NOW" "$ACS" | openssl base64 -A)
curl -s "$BASE/saml-idp/$APP/sso" --data-urlencode SAMLRequest="$REQUEST" --data-urlencode RelayState=xyz -o form.html

# 3. The page posts SAMLResponse to the ACS URL by itself; decode it to look at the signed response.
sed -n 's/.*name="SAMLResponse" value="\([^"]*\)".*/\1/p' form.html | openssl base64 -d -A > response.xml
grep -o 'InResponseTo="[^"]*"' response.xml | head -1

El último comando muestra InResponseTo="_req1". Su proveedor de servicios valida response.xml con el certificado de idp-metadata.xml.

Endpoints SCIM 2.0

Use los endpoints SCIM para probar un cliente SCIM, como un conector de aprovisionamiento o un script que crea usuarios y grupos, sin red. Cada <directory_id> es un directorio separado y vacío que vive mientras dure el proceso.

Ejemplo: aprovisionar un usuario con curl

El ejemplo necesita curl y jq. Inicie primero el servidor en otra terminal.

SCIM=http://127.0.0.1:4010/scim/v2/dir_local
AUTH='Authorization: Bearer keenauth-mock-scim-token'
CT='Content-Type: application/scim+json'

# 1. Create a user; the response carries the id, meta.version and an ETag header.
USER_ID=$(curl -s "$SCIM/Users" -H "$AUTH" -H "$CT" -d '{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "userName": "ada@example.test",
  "name": {"givenName": "Ada", "familyName": "Lovelace"},
  "emails": [{"value": "ada@example.test", "type": "work", "primary": true}]
}' | jq -r .id)

# 2. Find it with a filter.
curl -s -G "$SCIM/Users" -H "$AUTH" --data-urlencode 'filter=userName eq "ada@example.test"' | jq .totalResults

# 3. Deactivate it with PATCH, guarded by the version you read.
curl -s -X PATCH "$SCIM/Users/$USER_ID" -H "$AUTH" -H "$CT" -H 'If-Match: W/"1"' -d '{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [{"op": "replace", "path": "active", "value": false}]
}' | jq -c '{active, version: .meta.version}'

# 4. Create a group with the user as a member, then delete the user.
curl -s "$SCIM/Groups" -H "$AUTH" -H "$CT" -d '{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
  "displayName": "Engineering",
  "members": [{"value": "'"$USER_ID"'"}]
}' | jq -c '.members[0] | {display, type}'
curl -s -o /dev/null -w '%{http_code}\n' -X DELETE "$SCIM/Users/$USER_ID" -H "$AUTH"

Los comandos muestran 1, {"active":false,"version":"W/\"2\""}, {"display":"ada@example.test","type":"User"} y 204.

API de gestión (/v1)

Use los endpoints de la API de gestión para probar en CI, sin red, el código que llama a la API de gestión de KeenAuth (un SDK, la CLI, un script de despliegue). Las rutas son las alojadas: use la URL base http://127.0.0.1:4010/v1 en lugar de la alojada y nada más cambia. Los endpoints se generan a partir del documento OpenAPI de la API de gestión incluido en la CLI, así que responde cada operación de esa versión de la API.

En qué se diferencia del entorno development. El servidor mock solo valida que el cuerpo sea un objeto JSON con los campos obligatorios; no se comprueban los formatos de los campos, las longitudes, las enumeraciones ni la unicidad, y un campo con el tipo equivocado se ignora. Ignora If-Match, Idempotency-Key y el resto de cabeceras y no devuelve ETag. No comprueba permisos, límites de plan, cuotas, límites de frecuencia ni la región, no enmascara datos personales, no envía correos, no ejecuta trabajos (un trabajo aceptado permanece como se creó) y tiene un solo entorno. Los registros existen solo mientras dure el proceso, como máximo 10.000. Use su entorno development para saber cómo se comporta la API real.

Ejemplo: crear, leer, modificar y eliminar con curl

El ejemplo necesita curl y jq. Inicie primero el servidor en otra terminal.

API=http://127.0.0.1:4010/v1
AUTH='Authorization: Bearer keenauth-mock-management-token'
CT='Content-Type: application/json'

# 1. Create an organization.
ORG_ID=$(curl -s "$API/organizations" -H "$AUTH" -H "$CT" -d '{"name": "Acme"}' | jq -r .id)

# 2. Read it back and list.
curl -s "$API/organizations/$ORG_ID" -H "$AUTH" | jq -c '{id: (.id | .[0:4]), name}'
curl -s "$API/organizations" -H "$AUTH" | jq -c '{count: (.data | length), list_metadata}'

# 3. Rename it with a merge patch.
curl -s -X PATCH "$API/organizations/$ORG_ID" -H "$AUTH" -H 'Content-Type: application/merge-patch+json' -d '{"name": "Acme Inc"}' | jq -r .name

# 4. Delete it; a second read is a 404 problem.
curl -s -o /dev/null -w '%{http_code}\n' -X DELETE "$API/organizations/$ORG_ID" -H "$AUTH"
curl -s "$API/organizations/$ORG_ID" -H "$AUTH" | jq -c '{status, code}'

# 5. Without the token.
curl -s "$API/organizations" | jq -c '{status, code}'

Los comandos muestran {"id":"org_","name":"Acme"}, {"count":1,"list_metadata":{"after":null,"before":null}}, Acme Inc, 204, {"status":404,"code":"not_found"} y {"status":401,"code":"unauthenticated"}.

No compatible

No hay reloj de pruebas, ni DPoP, ni PAR, ni objetos de solicitud, ni flujo de dispositivo, ni client credentials, ni intercambio de tokens, ni cierre de sesión o revocación, ni páginas alojadas. El proveedor de identidad SAML no tiene cierre de sesión único, ni aserciones cifradas, ni binding de artefacto, ni inicio de sesión iniciado por el IdP. Los endpoints SCIM no tienen operaciones masivas, ordenación, /Me ni grupos anidados, y el filtro no admite or, not, paréntesis ni gt/ge/lt/le. Use su entorno development para probarlos.