Este conteúdo foi traduzido por máquina para sua conveniência e a Huawei Cloud não pode garantir que o conteúdo foi traduzido com precisão. Para exibir o conteúdo original, use o link no canto superior direito para mudar para a página em inglês.
Atualizado em 2023-02-16 GMT+08:00

IdP initiated

Esta seção usa o script Client4ShibbolethIdP como um exemplo para descrever como obter um token de autenticação federado no modo IdP-initiated. O script Client4ShibbolethIdP simula um usuário fazendo login em um sistema IdP usando um navegador, ajudando você a desenvolver seu próprio script cliente IdP.

Pré-requisitos

  • O servidor de IdP suporta autenticação de identidade federada IdP-initiated.
  • A biblioteca Python BeautifulSoup 4 foi instalada no cliente.

Fluxograma

A figura a seguir mostra o processo de autenticação de federação IdP-initiated.

Figura 1 Fluxograma (IdP-initiated)

Descrição

  1. O cliente visita o link de login fornecido pelo IdP para login IdP-initiated e define o endereço de nuvem pública (entityID no arquivo de metadados do sistema de nuvem) no link de login.
  2. O cliente exibe a página de login do IdP, permitindo que os usuários enviem informações de identidade ao IdP para autenticação.
  3. Depois de autenticar o usuário, o IdP constrói uma asserção contendo as informações de identidade do usuário e envia uma SAML response ao cliente.
  4. O cliente encapsula a SAML response e a encaminha para o sistema de nuvem para chamar a API usada para obter um token federado no modo IdP-initiated.
  5. O sistema em nuvem verifica e autentica a afirmação, gera uma credencial de acesso temporária conforme as regras de conversão de identidade do usuário configuradas para o provedor de identidade.
  6. O usuário pode acessar recursos de nuvem pública com base nas permissões atribuídas.

Implementação no Cliente

Esta seção usa o script Client4ShibbolethIdP.py para descrever como implementar a autenticação de identidade federada para acesso API/CLI ao sistema de nuvem a partir de um IdP.

  1. Configure o URL de login do IdP.

    Tabela 1 URLs de login de produtos IdP comuns

    IDP

    Parâmetro SP em URL

    Exemplo de URL de login

    ADFS

    logintorp

    https://adfs-server.contoso.com/adfs/ls/IdpInitiatedSignon.aspx?logintorp=https://iam.example.com

    Shibboleth

    providerId

    https://idp.example.org/idp/profile/SAML2/Unsolicited/SSO?providerId=iam.example.com

    SimpleSAMLphp

    spentityid

    https://idp.example.org/simplesaml/saml2/idp/SSOService.php?spentityid=iam.example.com

    Após a configuração, digite um URL de login na barra de endereços de um navegador. A seguinte página é exibida.

    Figura 2 Página de login
    Script Client4ShibbolethIdP:
    import sys
    import requests
    import getpass
    import re
    from bs4 import BeautifulSoup
    from urlparse import urlparse
    
    # SSL certificate verification: Whether or not strict certificate
    # verification is done, False should only be used for dev/test
    sslverification = True
    
    # Get the federated credentials from the user
    print "Username:",
    username = raw_input()
    password = getpass.getpass()
    print ''
    
    session = requests.Session()
    
    # The initial url that starts the authentication process.
    idp_entry_url = 'https://idp.example.com/idp/profile/SAML2/Unsolicited/SSO?providerId=https://iam.example.com'
    
    # Programmatically get the SAML assertion,open the initial IdP url# and follows all of the HTTP302 redirects, and gets the resulting# login page
    formresponse = session.get(idp_entry_url, verify=sslverification)
    # Capture the idp_authform_submit_url,which is the final url after# all the 302s
    idp_authform_submit_url = formresponse.url

  1. O cliente usa o Beautifulsoup 4 para capturar as informações do usuário e a ação solicitada e, em seguida, constrói e envia uma solicitação de autenticação de identidade para o IdP.

    O cliente adquire todos os dados do formulário enviados através da página de login.

    Figura 3 Informações de autenticação (1)

    Script Client4ShibbolethIdP:

    # Parse the response and extract all the necessary values in order to build a dictionary of all of the form values the IdP expects
    formsoup = BeautifulSoup(formresponse.text.decode('utf8'), "lxml")
    payload = {}
    
    for inputtag in formsoup.find_all(re.compile('(INPUT|input)')):
        name = inputtag.get('name', '')
        value = inputtag.get('value', '')
        if "username" in name.lower():
            payload[name] = username
        elif "password" in name.lower():
            payload[name] = password
        else:
            payload[name] = value
    
    for inputtag in formsoup.find_all(re.compile('(FORM|form)')):
        action = inputtag.get('action')
        if action:
            parsedurl = urlparse(idp_entry_url)
            idp_authform_submit_url = parsedurl.scheme + "://" + parsedurl.netloc + action
    
    # please test on browser first, add other parameters in payload
    payload["_eventId_proceed"] = ""
    
    formresponse = session.post(
        idp_authform_submit_url, data=payload, verify=sslverification)

  2. O cliente analisa a próxima página. (Alguns IdPs exibem uma página de atributos de usuário.)

    O cliente adquire todos os dados do formulário enviados através da página de login.

    Figura 4 Informações de autenticação (2)

    Script Client4ShibbolethIdP:

    # In shebbleth IdP v3, browser will show attributes page for user,# so we need parse the page
    formsoup = BeautifulSoup(formresponse.text.decode('utf8'), "lxml")
    payload = {}
    
    # Add other form data required from browser to payload
    _shib_idp_consentIds = []
    for inputtag in formsoup.find_all(re.compile('input')):
        name = inputtag.get("name")
        value = inputtag.get("value")
        if name == "_shib_idp_consentIds":
            _shib_idp_consentIds.append(value)
    payload["_shib_idp_consentIds"] = _shib_idp_consentIds
    payload["_shib_idp_consentOptions"] = "_shib_idp_rememberConsent"
    payload["_eventId_proceed"] = "Accept"
    
    # user can get the action url from the html file
    nexturl = "https://idp.example.com/idp/profile/SAML2/Unsolicited/SSO?execution=e1s2"
    
    for inputtag in formsoup.find_all(re.compile('(FORM|form)')):
        action = inputtag.get('action')
        if action:
            parsedurl = urlparse(idp_entry_url)
            nexturl = parsedurl.scheme + "://" + parsedurl.netloc + action
    
    response = session.post(
        nexturl, data=payload, verify=sslverification)

  3. Se a autenticação for bem-sucedida, o cliente analisará a resposta SAML enviada pelo IdP.

    Script Client4ShibbolethIdP:

    # Decode the response and extract the SAML assertion
    soup = BeautifulSoup(response.text.decode('utf8'), "lxml")
    SAMLResponse = ''
    
    # Look for the SAMLResponse attribute of the input tag
    for inputtag in soup.find_all('input'):
        if (inputtag.get('name') == 'SAMLResponse'):
            SAMLResponse = inputtag.get('value')
    
    # Better error handling is required for production use.
    if (SAMLResponse == ''):
        print 'Response did not contain a valid SAML assertion, please troubleshooting in Idp side.'
        sys.exit(0)

  4. Obtenha um unscoped token. Para mais detalhes, consulte IdP initiated.

    Script Client4ShibbolethIdP:

    # Set headers
    headers = {}
    headers["X-Idp-Id"] = "test_local_idp"
    
    # IAM API url: get unscoped token on IDP initiated mode
    sp_unscoped_token_url = "https://iam.example.com/v3.0/OS-FEDERATION/tokens"
    
    # Set form data
    payload = {}
    payload["SAMLResponse"] = SAMLResponse
    response = session.post(
        sp_unscoped_token_url, data=payload, headers=headers, verify=sslverification)
    
    # Debug only
    print(response.text)
    print "Status Code: " + str(response.status_code)
    if response.status_code != 201:
        sys.exit(1)
    
    unscoped_token = response.headers.get("X-Subject-Token") if "X-Subject-Token" in response.headers.keys() else None
    if unscoped_token:
        print ">>>>>>X-Subject-Token: " + unscoped_token

  5. Obtenha um scoped token. Para mais detalhes, consulte Obtenção de um scoped token.

    Script Client4ShibbolethIdP:

    payload = {
        "auth": {
            "identity": {
                "methods": ["token"],
                "token": {
                    "id": unscoped_token
                }
            },
            "scope": {
                "project": {
                    "name": "{region_id}_test1"
                }
            }
        }
    }
    
    sp_scoped_token_url = "https://10.120.171.90:31943/v3/auth/tokens"
    
    response = session.post(
        sp_scoped_token_url, json=payload, verify=sslverification)
    
    # Debug only
    print "Status Code: " + str(response.status_code)
    if response.status_code != 201:
        print response.text
        sys.exit(1)
    
    scoped_token = response.text if response.status_code == 201 else None
    if scoped_token:
        print ">>>>>>Scoped Token:" + scoped_token

  6. Obtenha uma chave de acesso temporária. Para mais detalhes, consulte Obtenção de uma chave de acesso temporária e SecurityToken através de um token.

    Script Client4ShibbolethIdP:

    # Set form data
    payload = {
        "auth": {
            "identity": {
                "methods": ["token"],
                "token": {
                    "duration_seconds": "900"
                }
            }
        }
    }
    
    # Set headers
    headers = {}
    headers["X-Auth-Token"] = unscoped_token
    
    sp_STS_token_url = "https://10.120.171.90:31943/v3.0/OS-CREDENTIAL/securitytokens"
    
    response = session.post(
        sp_STS_token_url, json=payload, headers=headers, verify=sslverification)
    
    # Debug only
    print "Status Code: " + str(response.status_code)
    if response.status_code != 201:
        print response.text
        sys.exit(1)
    
    sts_token = response.text if response.status_code == 201 else None
    if sts_token:
        print ">>>>>>STS Token:" + sts_token