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.
![](https://support.huaweicloud.com/intl/pt-br/api-iam/pt-br_image_0163397958.png)
Descrição
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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 loginScript 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
- 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)
- 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)
- 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)
- 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
- 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
- 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