Especificação de integração SSO e SCIM
Valores e comportamento para a integração OIDC, SAML 2.0 e SCIM 2.0.
Para a ordem de configuração na tela, consulte SSO e SCIM.
Em {API} da tabela, use o endereço da API do Keural do ambiente que você usa (por exemplo, https://api.keural.ai). Para o valor real, use o endereço exibido em Gerenciamento da organização → Configurações de SSO.
Resumo dos valores de registro
| Item | Valor |
|---|---|
| URI de redirecionamento OIDC | {API}/api/sso/callback |
| Início de login OIDC·SAML | {API}/api/sso/{orgId}/login |
| EntityID do SP SAML | {API}/api/sso/saml/metadata |
| URL de ACS SAML | {API}/api/sso/saml/callback |
| URL base do SCIM | {API}/scim/v2 |
O login sempre começa no Keural (SP-initiated). Ao informar um e-mail de domínio cadastrado na tela de login, o usuário é direcionado ao endereço de início de login. Em caso de sucesso, o usuário vai para a tela inicial do Keural; em caso de falha, vai para /login?error=sso.
OIDC
| Item | Comportamento |
|---|---|
| Fluxo | Authorization Code |
| Requisição authorize | response_type=code, client_id, redirect_uri, scope=openid email profile, state, nonce |
| state · nonce | De uso único e válidos por 10 minutos. Se a janela de login ficar aberta por mais de 10 minutos, o login é refeito desde o início. |
| Troca de token | POST no token endpoint, application/x-www-form-urlencoded. A autenticação do cliente é client_secret_post (client_id e client_secret no corpo). |
| Assinatura do ID token | Aceita somente RS256. A chave é localizada em jwks_uri pelo kid. |
| Validação do ID token | Assinatura, exp, aud contendo o client_id, nonce igual, e iss igual à Issuer URL (a / final é ignorada). |
Claim email do ID token. Se não existir, o userinfo endpoint é consultado com Authorization: Bearer <access_token> e o email é lido dele. | |
| Nome | Claim name do ID token |
| Endpoints | Localizados em /.well-known/openid-configuration da Issuer URL. Para um IdP que não possa ser encontrado, informe diretamente os endereços de authorization, token, JWKS e userinfo em Abrir configurações avançadas. |
| Tempo limite | 15 segundos para cada chamada ao IdP |
A aplicação no IdP deve permitir client_secret_post. Se a configuração permitir apenas client_secret_basic ou private_key_jwt, a troca de token falhará.
SAML 2.0
| Item | Comportamento |
|---|---|
| Requisição | Envia um AuthnRequest pelo binding HTTP-Redirect. A requisição não é assinada. |
| Conteúdo da requisição | Destination=URL de SSO do IdP, AssertionConsumerServiceURL=URL de ACS, ProtocolBinding=HTTP-POST, Issuer=EntityID do SP, NameIDPolicy Format=…:nameid-format:unspecified, AllowCreate=true |
| Resposta | Binding HTTP-POST com SAMLResponse e RelayState. RelayState deve ser retornado exatamente como o Keural o enviou. |
| Assinatura | A Response ou a Assertion deve ter uma assinatura válida. A chave de verificação é somente o certificado cadastrado na tela. |
| Asserção | A resposta deve conter exatamente uma asserção. Asserções criptografadas (EncryptedAssertion) não são aceitas. |
| Status | StatusCode igual a urn:oasis:names:tc:SAML:2.0:status:Success |
| Issuer | Se você informou o EntityID do IdP, deve ser igual ao Issuer da asserção |
| Condições | NotBefore e NotOnOrAfter (tolerância de 300 segundos), Audience=EntityID do SP |
| SubjectConfirmationData | Recipient=URL de ACS, NotOnOrAfter (tolerância de 300 segundos), InResponseTo=ID da requisição enviada pelo Keural |
Atributo cujo Name ou FriendlyName seja um dos seguintes (sem diferenciar maiúsculas): email, mail, emailAddress, E-Mail-Addresses, http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress. Se não existir, usa-se o NameID que contenha @. | |
| Nome | displayName, name, cn, http://schemas.microsoft.com/identity/claims/displayname |
| Certificado | Um certificado X.509. Pode estar em PEM ou em Base64 (DER). Para trocar, informe o novo certificado e salve. |
| Metadados | Em vez de enviar o XML de metadados do IdP, informe três valores: EntityID do IdP, URL de SSO do IdP e certificado. |
Identificação do usuário
| Item | Comportamento |
|---|---|
| Critério para encaminhar ao SSO | Quando o texto após @ do e-mail é exatamente igual a um item da lista de domínios de e-mail (sem diferenciar maiúsculas). Subdomínios são cadastrados separadamente. |
| Busca da conta | Procura a conta do Keural pelo e-mail (em minúsculas) enviado pelo IdP. |
| Se a conta não existir | Se Criar usuários automaticamente no primeiro login (JIT) estiver ativado, a conta é criada; se estiver desativado, o login é recusado. |
| Entrada na organização | Se não for membro da organização, entra como membro. Se os assentos estiverem cheios ou se a conta pertencer a outra organização, não entra, e apenas o login é permitido. |
| Condição para salvar o domínio de e-mail | Domínio verificado por TXT no DNS, exceto domínios de e-mail públicos |
Verificação de domínio
| Item | Valor |
|---|---|
| Tipo de registro | TXT |
| Host | O domínio cadastrado exatamente como está (por exemplo, acme.com). Não use subdomínio com prefixo. |
| Valor | keural-verify=<UUID>, exatamente o valor exibido na tela |
| Momento da consulta | Consultado uma vez, ao clicar em Confirmar verificação. |
SCIM 2.0
| Item | Valor |
|---|---|
| URL base | {API}/scim/v2 |
| Autenticação | Authorization: Bearer <token SCIM>. O token começa com scim_ e só é exibido uma vez, na emissão. |
| Content-Type | Requisição application/scim+json ou application/json; resposta application/scim+json |
| Códigos de status | Retorna o código de status HTTP real. O corpo de erro segue o formato SCIM Error (schemas, status, detail, scimType). |
Endpoints
| Método | Caminho | Comportamento |
|---|---|---|
GET | /Users | Lista. filter=userName eq "…", startIndex (padrão 1), count (padrão 100, máximo 200) |
GET | /Users/{id} | Consulta de um usuário |
POST | /Users | Criação (201). Se o mesmo e-mail já existir, retorna 409. |
PATCH | /Users/{id} | Altera active, displayName, name.formatted e name.givenName |
PUT | /Users/{id} | Aplica displayName, name e active. Se active for omitido, o usuário é considerado ativo. |
DELETE | /Users/{id} | Suspende a conta (204). Não apaga os dados. |
GET | /Groups, /Groups/{id} | Consulta dos dois grupos fixos. filter=displayName eq "…" |
PATCH | /Groups/{id} | Adiciona, remove ou substitui membros |
GET | /ServiceProviderConfig, /ResourceTypes, /Schemas | Consulta dos recursos suportados |
Atributos do usuário
| Atributo | Uso |
|---|---|
userName | E-mail. Se ausente, usa-se emails[0].value. |
displayName · name.formatted · name.givenName+name.familyName | Nome de exibição |
active | false suspende (bloqueia o login); true restaura |
id | ID do usuário no Keural. Vem na resposta. |
O externalId não é armazenado. Para localizar um usuário no IdP, use o filtro userName.
Grupos
| id | displayName | Ao adicionar um membro | Ao remover um membro |
|---|---|---|---|
keural-admins | Keural Admins | Administrador | Membro |
keural-members | Keural Members | Membro | Sem alteração |
O papel do proprietário da organização não é alterado pelo SCIM. Criar e excluir grupos (POST·DELETE /Groups) retornam 501. O value de um membro do grupo é o ID do usuário no Keural (id de /Users).
Escopo de suporte
| Recurso | Suportado |
|---|---|
| PATCH | Sim |
| Filtros | userName eq, displayName eq |
| Bulk · ordenação · ETag · alteração de senha | Não |
Erros
| Status | scimType | Causa |
|---|---|---|
400 | invalidValue | userName e emails ausentes |
401 | — | Token ausente ou incorreto, ou provisionamento SCIM desativado |
404 | — | O usuário ou grupo não pertence a esta organização |
409 | uniqueness | Já existe conta com o mesmo e-mail, ou o limite de assentos foi excedido |
501 | — | Criação ou exclusão de grupos |