I would like to test SAML autetification for Keycloak test should include basic login and logout.
I wanna use python3-saml libary.
My code does not work correctly the test is deselected.
I also don’t know if this is the right way or if I have to create an web app, for example through flask.
Could someone help me?
code bellow :
mport pytest
import requests
from onelogin.saml2.auth import OneLogin_Saml2_Auth
from onelogin.saml2.utils import OneLogin_Saml2_Utils
import xml.etree.ElementTree as ET
from urllib.parse import urlparse, urlencode
from bs4 import BeautifulSoup
KEYCLOAK_USERNAME = 'user'
KEYCLOAK_PASSWORD = 'password'
KEYCLOAK_LOGIN_URL = 'keycloackloginurl.com'
def parse_saml_settings(xml_file):
tree = ET.parse(xml_file)
root = tree.getroot()
def get_text(element, tag):
return element.find(tag).text
sp = root.find('sp')
idp = root.find('idp')
saml_settings = {
"strict": True,
"debug": True,
"sp": {
"entityId": get_text(sp, 'entityId'),
"assertionConsumerService": {
"url": get_text(sp.find('assertionConsumerService'), 'url'),
"binding": get_text(sp.find('assertionConsumerService'), 'binding')
},
"singleLogoutService": {
"url": get_text(sp.find('singleLogoutService'), 'url'),
"binding": get_text(sp.find('singleLogoutService'), 'binding')
},
"NameIDFormat": get_text(sp, 'NameIDFormat'),
"x509cert": get_text(sp, 'x509cert'),
"privateKey": get_text(sp, 'privateKey')
},
"idp": {
"entityId": get_text(idp, 'entityId'),
"singleSignOnService": {
"url": get_text(idp.find('singleSignOnService'), 'url'),
"binding": get_text(idp.find('singleSignOnService'), 'binding')
},
"singleLogoutService": {
"url": get_text(idp.find('singleLogoutService'), 'url'),
"binding": get_text(idp.find('singleLogoutService'), 'binding')
},
"x509cert": get_text(idp, 'x509cert')
}
}
return saml_settings
def prepare_request_dict(url):
url_data = urlparse(url)
return {
'https': 'on' if url_data.scheme == 'https' else 'off',
'http_host': url_data.netloc,
'script_name': url_data.path,
'server_port': url_data.port if url_data.port else '443' if url_data.scheme == 'https' else '80',
'get_data': {},
'post_data': {}
}
def saml_auth():
saml_settings = parse_saml_settings('saml_config.xml')
req = prepare_request_dict('http://localhost:8000/')
auth = OneLogin_Saml2_Auth(req, old_settings=saml_settings)
return auth
def get_saml_response_from_keycloak(login_url, username, password):
# Start a session
session = requests.Session()
# Get the SAML login form from Keycloak
response = session.get(login_url)
response.raise_for_status()
# Parse the login form
soup = BeautifulSoup(response.text, 'html.parser')
form = soup.find('form')
action = form['action']
# Extract form fields
form_data = {field['name']: field['value'] for field in form.find_all('input') if field.get('name')}
form_data.update({'username': username, 'password': password})
# Submit the form with user credentials
login_response = session.post(action, data=form_data)
login_response.raise_for_status()
# Extract SAMLResponse from the form submitted by Keycloak after successful login
soup = BeautifulSoup(login_response.text, 'html.parser')
saml_response = soup.find('input', {'name': 'SAMLResponse'})['value']
return saml_response
def test_saml_login(saml_auth):
# Create a SAML authentication request
saml_request = saml_auth.login()
# Extract the SAMLRequest URL and parameters
url_data = urlparse(saml_request)
params = {param.split('=')[0]: param.split('=')[1] for param in url_data.query.split('&')}
# Simulate user login to Keycloak and get SAMLResponse
saml_response = get_saml_response_from_keycloak(KEYCLOAK_LOGIN_URL, KEYCLOAK_USERNAME, KEYCLOAK_PASSWORD)
# Handle the SAML response
request_data = prepare_request_dict('http://localhost:8000/acs/')
request_data['post_data']['SAMLResponse'] = saml_response
saml_auth.process_response()
# Check for errors and authentication status
errors = saml_auth.get_errors()
assert len(errors) == 0, f"Errors occurred: {', '.join(errors)}"
assert saml_auth.is_authenticated(), "Authentication failed"
if __name__ == "__main__":
pytest.main()
I expect succesfull login assertion
New contributor
Marek Oršula is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.