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 2024-08-31 GMT+08:00

IdP iniciado

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

Pré-requisitos

  • Seu servidor de IdP oferece suporte à autenticação de identidade federada iniciada pelo IdP.
  • A biblioteca de Python BeautifulSoup 4 foi instalada no cliente.

Fluxograma

A figura a seguir mostra o processo de autenticação de federação iniciada pelo IdP.

Figura 1 Fluxograma (iniciado pelo IdP)

Descrição

  1. O cliente visita o link de logon fornecido pelo IdP para logon iniciado pelo IdP e define o endereço de nuvem pública (entityID no arquivo de metadados do sistema de nuvem) no link de logon.
  2. O cliente exibe a página de logon 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 resposta SAML ao cliente.
  4. O cliente encapsula a resposta SAML e a encaminha para o sistema de nuvem para chamar a API usada para obter um token federado no modo iniciado pelo IdP.
  5. O sistema de nuvem verifica e autentica a asserção e gera uma credencial de acesso temporária de acordo com 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 de API/CLI ao sistema de nuvem a partir de um IdP.

Você pode baixar o script aqui:

https://obs-iam-download01.obs.cn-north-1.myhwclouds.com/non-ecp-script/Client4ShibblethIdP.py

  1. Configure o URL de logon do IdP.

    Tabela 1 URLs de logon de produtos de IdP comuns

    IdP

    Parâmetro de SP em URL

    Exemplo de URL de logon

    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, insira um URL de logon na barra de endereços de um navegador. A seguinte página é exibida.

    Figura 2 Página de logon
    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 por meio da página de logon.

    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 por meio da página de logon.

    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 token sem escopo. Para mais detalhes, consulte Obtenção de um token sem escopo (iniciado pelo IdP).

    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 token com escopo. Para mais detalhes, consulte Obtenção de um token com escopo.

    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 de um token de segurança por meio 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