Skip to content

PhoneTrackTeam/identity-provider-example

Repository files navigation

Identity Provider - IdP

Iniciando projeto

docker-compose up -d --build

Acessando projeto localhost

http://localhost:8081/

home IdP

Configuração Phonetrack

<?php
#./config.php
return [
    'phonetrack' => [
        'host' => 'https://phonetrack.app',
        'account_id' => 1, // Informe aqui a Conta que o usuario tem acesso
        'units_id' => '2' // Informe aqui as Unidades que o usuario tem acesso: 1,2,3,4,5
    ],
    'idp' => [
        'name' => 'idpexample' // Nome do Provedor de identidade: NameIdP
    ]
];

Rotas disponiveis

  • / - Home
  • /info.php - Settings
  • /login.php - Sign in
  • logout.php - Sign out
  • /sso.php - SSO with SAML
  • /redirect.php - Redirect SAML Response

Criando certificado x509

openssl req -newkey rsa:3072 -new -x509 -days 3652 -nodes -out certificate.crt -keyout private_key.pem

Variavel de ambiente com caminho para private key e certificate

PRIVATE_KEY_PATH=/path/to/my/private_key.pem
CERTIFICATE_PATH=/path/to/my/certificate.crt

Login SAML

idp-fluxo

O que eu preciso entender desse fluxo?

SSO

O arquivo sso.php é responsavel por receber o SAMLRequest criptografado e RelayState criado a partir do Provedor de Serviço.

O sso.php faz a descriptografia do SAMLRequest e extrai os metadados.

Metadado Descrição
ID Identificador da requisição SAML
AssertionConsumerServiceURL Esse campo contém o URL que será utilizado para enviar o POST com SAMLResponse e RelayState.
IssueInstant Contém a data e hora de inicio da requisição SAML. Essa data é importante porque é utilizada para validar se a requesição está expirada. Ex.: 2022-10-10T12:33:28Z

Redirect

O arquivo redirect.php é responsavel por formatar e criptografar o SAMLResponse.

Formatando um SAMLResponse

O SAMLResponse é composto de algumas informações importante para garantir a confiabilidade dos dados enviado para o Provedor de Serviço.

Metadado Descrição
IssueInstant Contém a data e hora de inicio da requisição SAML. Essa data é importante porque é utilizada para validar se a requesição está expirada. Ex.: 2022-10-10T12:33:28Z
InResponseTo Uma referência ao identificador da solicitação. Deve corresponder ao valor do atributo ID do SAMLRequest correspondente.
Issuer Identifica a entidade que gerou a mensagem de resposta
Signature Contém uma assinatura digital que garante a autenticidade e integridade dos metadados.
Status Um código que representa o status da solicitação correspondente
Assertion O elemento Assertion é um tipo complexo. Este tipo especifica informações que são comuns a todas as asserções, incluindo os seguintes elementos e atributos
Assertion Metadado Descrição
Issuer Identifica a entidade que gerou a mensagem de resposta
Subject Identifica o principal autenticado. O nameID com o nome do usuario autenticado.
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">Teste 01</saml:NameID>
Conditions As condições sob as quais a afirmação deve ser considerada válida
AuthnStatement Descreve a forma de autenticação no provedor de identidade
AttributeStatement Atributos associado ao usuario autenticado.
A Phonetrack depende do email, account_id e units_id

Exemplo de XML SAMLResponse

<?xml version="1.0"?>
<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Version="2.0" ID="pfxb1e42802-f516-1c47-427a-aefb30d24db8" IssueInstant="2022-10-10T12:33:28Z" InResponseTo="ONELOGIN_aa3753b2987ae987f9cd62814f052586826a4c22">
    <saml:Issuer>http://localhost:8081</saml:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
            <ds:Reference URI="#pfxb1e42802-f516-1c47-427a-aefb30d24db8">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
                <ds:DigestValue>OMG8i4tYRYmHpCRy3e1SevzUQKYi48YTneIUyO7TA2w=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>qqGrvo96nlkDQXtOxsL554ycZVkwAVVMIxXicnHiCAHV</ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>MIIEmTCCAwGgAwIBAgIULJp5Dqvulmk</ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
    </samlp:Status>
    <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="2.0" ID="_be97c5c4-4897-11ed-b9cf-0242c0a8b002" IssueInstant="2022-10-10T12:33:28Z">
        <saml:Issuer>http://localhost:8081</saml:Issuer>
        <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">Teste 01</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData NotOnOrAfter="2022-10-10T12:36:28Z" Recipient="" InResponseTo="ONELOGIN_aa3753b2987ae987f9cd62814f052586826a4c22" />
            </saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="2022-10-10T12:30:28Z" NotOnOrAfter="2022-10-10T12:36:28Z">
            <saml:AudienceRestriction>
                <saml:Audience />
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AuthnStatement AuthnInstant="2022-10-10T12:33:28Z" SessionNotOnOrAfter="2022-10-11T12:33:28Z" SessionIndex="85f33aa7b040798b7c6849e97dca3605">
            <saml:AuthnContext>
                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
            </saml:AuthnContext>
        </saml:AuthnStatement>
        <saml:AttributeStatement>
            <saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" Name="units_id">
                <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">2</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" Name="email">
                <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">teste01@example.com</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" Name="account_id">
                <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">1</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
    </saml:Assertion>
</samlp:Response>

Exemplo de SAMLResponse criptografado

$xml_saml_response = "AQUI VAI O XML";
$saml_response = base64_encode($xml_saml_response);

Formulario de resposta

É enviar um formulario POST contendo SAMLResponse criptografado e RelayState com o URL de redirecionamento no Provedor de Serviço.

<form method="post" action="http://sp.example.com/path/to/saml/acs/login">
        <input name="SAMLResponse" type="hidden" value='OMG8i4tYRYmHpCRy3e1SevzUQKYi48Y'>
        <input name="RelayState" type="hidden" value="/path/to/redirect">
</form>

Exemplo Backend public/redirect.php

Exemplo Frontend src/View/redirect.phtml

URL de redirecionamento

O RelayState contém o URL que o Provedor de Serviço - SP utiliza para redirecionar após receber a resposta do Provedor de Identidade - IdP.

Esse RelayState é enviado pelo SP para o IdP e quando o IdP enviar a resposta para o SP esse RelayState deve ser enviado tambem.

Você pode ver a presença do RelayState na imagem de fluxo logo a encima.

Configuração para integração do IdP

Essas são as informações para integrar com o Provedor de identidade.

Acesse http://localhost:8081/info.php

settings idp

Agora vamos falar de código

Manipulando SAMLRequest

Para tratar um SAMLRequest é preciso:

  • Obter o SAMLRequest que o Provedor de Serviço passou no URL http://localhost:8081/sso.php
  • Obtido o SAMLRequest agora devemos descriptografar esse base64 recebido.
  • Agora precisamos inflar esse decode

Teremos um código semelhante a esse:

<?php
# ./public/sso.php
$decoded = base64_decode($_GET['SAMLRequest']);
$xml_saml_request = gzinflate($decoded);

Nesse ponto já temos um XML com os metadados do SAMLRequest

Para trabalhar de forma mais produtiva vamos utiliza a extensão DOM nativa no PHP. Essa extensão vai facilitar a manipulação do XML.

Segue um exemplo manipulando o XML do SAMLRequest

<?php
# ./public/sso.php
$document = new DOMDocument();
$document->loadXML($xml_saml_request);
$xml = $document->firstChild;

echo $xml->getAttribute('AssertionConsumerServiceURL');
echo $xml->getAttribute('ID');
echo $xml->getAttribute('IssueInstant');

Gerando um SAMLResponse

Vamos quebrar nossa resposta em partes e no final vamos juntar todas para criar nosso SAMLResponse assinado. Vamos seguir essa ordem:

  • Issuer
  • Status
  • Assertion
  • Response
  • Signature

Dados fake para teste

Para auxiliar na criação dos objetos vamos criar algumas variaveis com dados fake

<?php
// Dados fake para teste
$requestId = 'ONELOGIN_aa3753b2987a26a4c22';
$sessionId = session_id()
$signedId = hash('sha256', uniqid($sessionId));
$entityId = 'http://localhost:8081';
$userName = 'Test Example';
$issueInstant = new \DateTime();

// Dados que a Phonetrack precisa para autenticar usuario
$attributes = [
    'units_id' => '1,2,3',
    'email' => 'test@example.com',
    'account_id' => 1,
];

Criando o Issuer

<?php
# ./public/redirect.php
use IdPExample\Issuer;

$issuer = new Issuer();
$issuer->setContent($entityId);

Criando o Status

<?php
# ./public/redirect.php
use IdPExample\Status;
use OneLogin\Saml2\Constants;

$status = new Status();
$status->setStatusCode(Constants::STATUS_SUCCESS);

Criando o Assertion

<?php
# ./public/redirect.php
use IdPExample\Build\AssertionBuild;

$assertionBuild = new AssertionBuild($issueInstant);
$assertionBuild
    ->issuer($entityId)
    ->conditions($issueInstant)
    ->authnStatement($sessionId, $issueInstant)
    ->attributeStatement($attributes)
    ->subject($userName, [
        'NotOnOrAfter' => clone $issueInstant,
        'Recipient' => '',
        'InResponseTo' => $requestId
    ]);

$assertion = $assertionBuild->getAssertion();

Criando o Response

<?php
# ./public/redirect.php
use IdPExample\Response;

$xmlResponse = new Response($signedId);
$xmlResponse->setIssueInstant($issueInstant);
$xmlResponse->setInResponseTo($requestId);
$xmlResponse->setIssuer($issuer);
$xmlResponse->setStatus($status);
$xmlResponse->setAssertion($assertion);

Assinando Response

<?php
# ./public/redirect.php
use IdPExample\Signature;

$signature = new Signature();
$signature->addSign($xmlResponse);

Agora já temos um XML assinado e podemos obter o SAMLResponse.

<?php
# ./public/redirect.php
$samlResponse = base64_encode($signature->getSAMLResponseSigned());

O $samlResponse é um XML SAMLResponse criptografado em base64. Esse hash é enviado via POST para o URL Assertion Consumer Service - ACS do Provedor de Serviço.

About

Exemplo de Provedor de Identidade

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published