Skip to content
Snippets Groups Projects
Commit ec2a36b4 authored by Saleem Latif's avatar Saleem Latif
Browse files

Third Party Authentication (SSO): Default values for SAML attributes

parent 20bd8621
No related merge requests found
# -*- coding: utf-8 -*-
# Generated by Django 1.11.15 on 2018-10-12 07:07
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('third_party_auth', '0021_sso_id_verification'),
]
operations = [
migrations.AddField(
model_name='samlproviderconfig',
name='default_email',
field=models.CharField(blank=True, help_text=b'Default value for email to be used if not present in SAML response.', max_length=255, verbose_name=b'Default Value for Email'),
),
migrations.AddField(
model_name='samlproviderconfig',
name='default_first_name',
field=models.CharField(blank=True, help_text=b'Default value for first name to be used if not present in SAML response.', max_length=255, verbose_name=b'Default Value for First Name'),
),
migrations.AddField(
model_name='samlproviderconfig',
name='default_full_name',
field=models.CharField(blank=True, help_text=b'Default value for full name to be used if not present in SAML response.', max_length=255, verbose_name=b'Default Value for Full Name'),
),
migrations.AddField(
model_name='samlproviderconfig',
name='default_last_name',
field=models.CharField(blank=True, help_text=b'Default value for last name to be used if not present in SAML response.', max_length=255, verbose_name=b'Default Value for Last Name'),
),
migrations.AddField(
model_name='samlproviderconfig',
name='default_username',
field=models.CharField(blank=True, help_text=b'Default value for username to be used if not present in SAML response.', max_length=255, verbose_name=b'Default Value for Username'),
),
]
......@@ -543,18 +543,33 @@ class SAMLProviderConfig(ProviderConfig):
attr_full_name = models.CharField(
max_length=128, blank=True, verbose_name="Full Name Attribute",
help_text="URN of SAML attribute containing the user's full name. Leave blank for default.")
default_full_name = models.CharField(
max_length=255, blank=True, verbose_name="Default Value for Full Name",
help_text="Default value for full name to be used if not present in SAML response.")
attr_first_name = models.CharField(
max_length=128, blank=True, verbose_name="First Name Attribute",
help_text="URN of SAML attribute containing the user's first name. Leave blank for default.")
default_first_name = models.CharField(
max_length=255, blank=True, verbose_name="Default Value for First Name",
help_text="Default value for first name to be used if not present in SAML response.")
attr_last_name = models.CharField(
max_length=128, blank=True, verbose_name="Last Name Attribute",
help_text="URN of SAML attribute containing the user's last name. Leave blank for default.")
default_last_name = models.CharField(
max_length=255, blank=True, verbose_name="Default Value for Last Name",
help_text="Default value for last name to be used if not present in SAML response.")
attr_username = models.CharField(
max_length=128, blank=True, verbose_name="Username Hint Attribute",
help_text="URN of SAML attribute to use as a suggested username for this user. Leave blank for default.")
default_username = models.CharField(
max_length=255, blank=True, verbose_name="Default Value for Username",
help_text="Default value for username to be used if not present in SAML response.")
attr_email = models.CharField(
max_length=128, blank=True, verbose_name="Email Attribute",
help_text="URN of SAML attribute containing the user's email address[es]. Leave blank for default.")
default_email = models.CharField(
max_length=255, blank=True, verbose_name="Default Value for Email",
help_text="Default value for email to be used if not present in SAML response.")
automatic_refresh_enabled = models.BooleanField(
default=True, verbose_name="Enable automatic metadata refresh",
help_text="When checked, the SAML provider's metadata will be included "
......@@ -643,10 +658,27 @@ class SAMLProviderConfig(ProviderConfig):
attrs = (
'attr_user_permanent_id', 'attr_full_name', 'attr_first_name',
'attr_last_name', 'attr_username', 'attr_email', 'entity_id')
attr_defaults = {
'attr_full_name': 'default_full_name',
'attr_first_name': 'default_first_name',
'attr_last_name': 'default_last_name',
'attr_username': 'default_username',
'attr_email': 'default_email',
}
# Defaults for missing attributes in SAML Response
conf['attr_defaults'] = {}
for field in attrs:
field_name = attr_defaults.get(field)
val = getattr(self, field)
if val:
conf[field] = val
# Default values for SAML attributes
default = getattr(self, field_name) if field_name else None
conf['attr_defaults'][field] = default
# Now get the data fetched automatically from the metadata.xml:
data = SAMLProviderData.current(self.entity_id)
if not data or not data.is_valid():
......
......@@ -211,6 +211,17 @@ class EdXSAMLIdentityProvider(SAMLIdentityProvider):
})
return details
def get_attr(self, attributes, conf_key, default_attribute):
"""
Internal helper method.
Get the attribute 'default_attribute' out of the attributes,
unless self.conf[conf_key] overrides the default by specifying
another attribute to use.
"""
key = self.conf.get(conf_key, default_attribute)
default = self.conf['attr_defaults'].get(conf_key) or None
return attributes[key][0] if key in attributes else default
@property
def saml_sp_configuration(self):
"""Get the SAMLConfiguration for this IdP"""
......@@ -242,6 +253,14 @@ class SapSuccessFactorsIdentityProvider(EdXSAMLIdentityProvider):
'country': 'country',
}
defaults_value_mapping = {
'defaultFullName': 'attr_full_name',
'firstName': 'attr_first_name',
'lastName': 'attr_last_name',
'username': 'attr_username',
'email': 'attr_email',
}
# Define a simple mapping to relate SAPSF values to Open edX-compatible values for
# any given field. By default, this only contains the Country field, as SAPSF supplies
# a country name, which has to be translated to a country code.
......@@ -260,7 +279,12 @@ class SapSuccessFactorsIdentityProvider(EdXSAMLIdentityProvider):
Get a dictionary mapping registration field names to default values.
"""
field_mapping = self.field_mappings
registration_fields = {edx_name: response['d'].get(odata_name, '') for odata_name, edx_name in field_mapping.items()}
value_defaults = self.conf.get('attr_defaults', {})
value_defaults = {key: value_defaults.get(value, '') for key, value in self.defaults_value_mapping.items()}
registration_fields = {
edx_name: response['d'].get(odata_name, value_defaults.get(odata_name, ''))
for odata_name, edx_name in field_mapping.items()
}
value_mapping = self.value_mappings
for field, value in registration_fields.items():
if field in value_mapping and value in value_mapping[field]:
......
RelayState=testshib&SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOlJlc3BvbnNlIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBEZXN0aW5hdGlvbj0iaHR0cDovL2V4YW1wbGUubm9uZS9hdXRoL2NvbXBsZXRlL3RwYS1zYW1sLyIgSUQ9Il9hMDdmZDlhMDg0ODM3M2U1NTMyMGRjMzQyNDk0ZWY1ZCIgSW5SZXNwb25zZVRvPSJURVNUSUQiIElzc3VlSW5zdGFudD0iMjAxNS0wNi0xNVQwMDowNzoxNS4xODhaIiBWZXJzaW9uPSIyLjAiPjxzYW1sMjpJc3N1ZXIgeG1sbnM6c2FtbDI9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6ZW50aXR5Ij5odHRwczovL2lkcC50ZXN0c2hpYi5vcmcvaWRwL3NoaWJib2xldGg8L3NhbWwyOklzc3Vlcj48c2FtbDJwOlN0YXR1cz48c2FtbDJwOlN0YXR1c0NvZGUgVmFsdWU9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2VzcyIvPjwvc2FtbDJwOlN0YXR1cz48c2FtbDI6RW5jcnlwdGVkQXNzZXJ0aW9uIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIj48eGVuYzpFbmNyeXB0ZWREYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyIgSWQ9Il9kYzc3ODI3YmY1ZGMzYjZmNGQzNjkzZWUzMTU2YmE1MiIgVHlwZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjRWxlbWVudCI%2BPHhlbmM6RW5jcnlwdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI2FlczEyOC1jYmMiIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyIvPjxkczpLZXlJbmZvIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj48eGVuYzpFbmNyeXB0ZWRLZXkgSWQ9Il85NzhhN2I2NDE5YTMxOGQ4NmUzMzE0Y2Y5YjFjOTEzZiIgeG1sbnM6eGVuYz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjIj48eGVuYzpFbmNyeXB0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjcnNhLW9hZXAtbWdmMXAiIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI%2BPGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIiB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyIvPjwveGVuYzpFbmNyeXB0aW9uTWV0aG9kPjxkczpLZXlJbmZvPjxkczpYNTA5RGF0YT48ZHM6WDUwOUNlcnRpZmljYXRlPk1JSUNzRENDQWhtZ0F3SUJBZ0lKQUpyRU5yOEVQZ3BjTUEwR0NTcUdTSWIzRFFFQkJRVUFNRVV4Q3pBSkJnTlZCQVlUQWtGVk1STXcKRVFZRFZRUUlFd3BUYjIxbExWTjBZWFJsTVNFd0h3WURWUVFLRXhoSmJuUmxjbTVsZENCWGFXUm5hWFJ6SUZCMGVTQk1kR1F3SGhjTgpNVFV3TmpFek1ERXdOVEUwV2hjTk1qVXdOakV5TURFd05URTBXakJGTVFzd0NRWURWUVFHRXdKQlZURVRNQkVHQTFVRUNCTUtVMjl0ClpTMVRkR0YwWlRFaE1COEdBMVVFQ2hNWVNXNTBaWEp1WlhRZ1YybGtaMmwwY3lCUWRIa2dUSFJrTUlHZk1BMEdDU3FHU0liM0RRRUIKQVFVQUE0R05BRENCaVFLQmdRRE0rTmY3SWVSZElJZ1lVa2U2c1Izbjdvc0hWWVh3SDZwYitPdnE4ajNoVW95OGt6VDlrSkYwUkIzaAozUTJWSjNaV2lRdFQ5NGZaWDJZWW9yVmRvR1ZLMk5XempMd2dwSFVzZ2ZlSnE1cENqUDBkMk9RdTlRdmpnNllPdFlQNlBOM2o3ZUs3CnBVY3hRdkljYVk5QVBERjU3dWEvelBzbTNVemJqaFJsSlpRVWV3SURBUUFCbzRHbk1JR2tNQjBHQTFVZERnUVdCQlRqT3lQdkF1ZWoKNXE0QzgwamxGclFtT2xzem16QjFCZ05WSFNNRWJqQnNnQlRqT3lQdkF1ZWo1cTRDODBqbEZyUW1PbHN6bTZGSnBFY3dSVEVMTUFrRwpBMVVFQmhNQ1FWVXhFekFSQmdOVkJBZ1RDbE52YldVdFUzUmhkR1V4SVRBZkJnTlZCQW9UR0VsdWRHVnlibVYwSUZkcFpHZHBkSE1nClVIUjVJRXgwWklJSkFKckVOcjhFUGdwY01Bd0dBMVVkRXdRRk1BTUJBZjh3RFFZSktvWklodmNOQVFFRkJRQURnWUVBVjV3MFN4alUKVEZXZkwzWkc2c2dBMGdLZjhhVjh3M0FsaWhMdDl0S0NSZ3JLNHNCSzl4bWZ3cC9mbmJkeGtIVTU4aW96STg5NEhxbXJSekNpYVJMVwpteTNXODY0MEUvWENhNlAraThFVDdSa3NnTko1Y0Q5V3RJU0hrR2MyZG5XNzYrMm52OGQyNEpLZUl4MndvSkF0c3BNeXd6cjBTb3hECklKcjQyTjZLdmprPTwvZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUwOURhdGE%2BPC9kczpLZXlJbmZvPjx4ZW5jOkNpcGhlckRhdGEgeG1sbnM6eGVuYz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjIj48eGVuYzpDaXBoZXJWYWx1ZT5sWEEvSGI2SlIxaW1UM2M1citrQU9taHVieVYvOUpqTUNzdkRJYlBEckxVR1g0aWFVbGl6c2d0dkdzRzdYOVpQWUxhc281U2ZlK1dTbVpKeW9tMGc0UU9HOWd6R3FIVGwybzFGMlJib0ZKS2FzaDZoQ011c2dSRmpJWElSUzdvTWJJTGxmcGhvcUN2c0pGdUpKY1FldU9SeWwyZmlrcUJSclhjNmwyMks2YzA9PC94ZW5jOkNpcGhlclZhbHVlPjwveGVuYzpDaXBoZXJEYXRhPjwveGVuYzpFbmNyeXB0ZWRLZXk%2BPC9kczpLZXlJbmZvPjx4ZW5jOkNpcGhlckRhdGEgeG1sbnM6eGVuYz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjIj48eGVuYzpDaXBoZXJWYWx1ZT5UQWdqL1d3ait2b0ppdHNhUE9IdmFSUHN3WE5oaHhEMmx2Q0t6MXJzQmtYbmJheVhlNmJucE1CMHg5aWpFMVdqOFV4YmtJQmhBMTEwRHhhTjZabkhReUs4amI3U29VU09jQkovUGxrT1NJc21zcS94dTVZTDJrdC9qdTdwRDR6K3BpcUlJbWRSVXdkcEhPdXFSVUxzUUJNU1NCRU5QT2sxQkRjcWZxb091N1g1VFIyOHE2eEwwUlFoV2NqMHBoTW9BMHdZS2ZFU0tacmRDQVRLcXVFcUJTRGJzRThNekh1cndiUkVkcjM5YnpBMGRNTm1zVFBFWmpsdkdqSEJmdVRaS3VPWXBoR3lFV1FVa29PbEtMQ1ROQ3VQYnhaWjFZNi80SGhlTGpQL3pnSU9ieWdLVkdadmNBSWpyTmZXNi9iQkJ0MVJjbndKV3pTZU5XR3hnd2hnZTJDank4RVFTUHJxbWZYK29VSVY3NExmT1NhV2JONXRwK3dtbzgveGlzWFErRysyZzA1ZnBiZEVmcEhacFZhMmFZY24xYWRtYy9uK3p1U0w2LzRTVWtXcTIvRHpRTTBWQVNQN2o0MXNIc0wwZEt2ZkhiQk5BcFB3NzdyTWdXRkwxcjVRajZiUmVjSElkQ3ozamZLcDZtdzBURzFQaUxCc2FXZ2wzYnZVR0lJNmxOWTg1TStFWHpoUnNCY29uVjgwUWFnKzBoTks3OWNteFkvOFByOGZkdXErMmgva3UxUzN2REo0cTlpR0FPaG1MUUFrWEQwWGF5Q1hXa0x1MEFyTmdOalNjaU55UXY2c3RmOUx1NGdUd1lKWUsyV0lWYUEvTzdMbUl2WmxkL0thL2VSaHdJQnV5YnpmemxWSVA0a2VVVmpldDVZMnZUVzA5bG02bWQzV1dmOTYrb21yNGVBQjllWjBmaFRxRkV4UzJkQVFqWi9JV21ZNnNXQXJCSkg4aEhya0IxdVBrQkZYTVFNbSs5T3ZKMWpnWXZtdVJUcHZzc1ZlL1MwWDhIVlVSdUpZVDVBY09YNHhuTWw0QkpXdnlLbzFFUms4bmRZOXJTTkJscGUrSXRUQXY5ZDgveVdJcGlYRVRLWGpKbTlVVWt6NnIyclhDUkN0VDhWa3J2M29jZmY0Z09nUjlTSWR0b21hU2w5RG9sTjVFL0ljTm1DUkhrbTR0U1J4bDNrNzNiMy8rNUxJNDhHc3l2c1VsNlNaZ1dCNmhSdDZaNDNuS2Iza3czOWd1cjk0VStrcURuUndub3lyeDVoc3N1NWRVVFNURkJPajhENGk0SjZwYi9sQ3FvWDVtR3lNODVJWnpxQk1Sa3IzeldPUzg3SVhBQm1uVDZ6aE1NdEpzN3EwRG9WZUhQbExUeUlVRHFMZWlaMjREQzN3Z1BjNmh0STVNeU1EZG5OM0hLczdnT3lhY3ppV280c3I1RGJCc3FqaFd1ZzJIanJEQ2hXZUszY1NuTlcwbkZCT1RJOFZMSFJXK2lhd3ZJWnUwZGdSenR1aEFjQ3lCelB0SHUrSzZlZmgyR0lNT0NhVVJCUzA3eGRETkw2MG9jOTBZZUlmOGV5WDFqV3ZDaDJZSnNxMDRtU3AySUFFQzFQSS9mc3lleGIrU2lMWTNzR1FyNEQ1bGx6ZHh6VEpKa2tYd2c4dHMxeklvSEx2TDdkQ29BRVNmNDJVVERFdWo4bGtadjYrM0JkNkwrM3Z6WFFPb2xwQ1kxeGRodVFOQjhsbG5KWHRNMmdtb1NEcmRwN1JzZWtTM2hkOWkxSkxkYWR1bW9oM0hmd0x6d0c4SkpCRkpmb3k0cGtzM05vMWFyT0lKRVBzZ3ZCMzZZUitScFFvc2hHM01PS0EwTUphcDNJbE5yQlVjdmw4WW5jSGkzbE9CUWpySFcrSURVVHhxZG9jdmw0NTBscmVUdkVoZXYraUFLU0J4alhNclNDQytaOWFIS1BJR2s4UzR2dWtudURIMUpsdTNLSFBwNFA5bnhSMnp3V3ZldktkYjNLdjZ3emhidmlxR0pPY05CeUZzRVJvNkEwSVVNVHQvOFJkQzJkZndyTjNBTHZ4dktrTmE0c3dEcElqYkRkb3RrZWgzT29FTVRETGE4M1R6Ym9ROFdWcDJLbEJiZDlWdXVNRm8xVUtrN2Q0dFh4VXRnWkZ3YlZQUWNzU21TV1dud1QvMFhxdDB0Yk8zQ0lnNkVZOHFXaUxoWU5naGw4eUhXTGIxbUUzVWNoSUhhVDBoWmNXTXVLMmtNbVpNMlJJeWVJY3o4M2NmY2lSWFJUb0g2TzFPenF5ZytBVUZiendibXQxR2d3V1hnMTdZQVJxSFViaDZwdktUMGJFRzdPUDRMZ0U4ajQvdTJoQjFraUFnUXpQSC84RHVCQlQwdkdOeElnKzhNWi9ObUFmUWRxODBlcVNQTDVpczlGbkZVei9GUzYzdEVCb0xYZnk5VzFRUjBsZ3VUY3o5b3l1dkdPdmVDZUt4RE9pZU9ZSktFTTlhVFVzVjRGc2c5M0NzMTQvRkhXQzJpclRKN1J3Ymg4eG1WUzBqUnVFQUdBejdETDNaSkFiRElLUUM5ZWZ2QUYxRHREVjZiVEI5cnNlczdsOWlDS3RnSnRWRE83Nmc5M2tWSGwvdXpYbVhwQ0NveS9XYStvVFErek5WL0lMbXAwVnorRnhJRHROUmcyL0V3eENyN042RW05ZmRibHgrMjYyWkdEVWVKcXcwNjB3L0RDTThiMDJmc2dyQTJ4NUVvcjF4a0tmcXMvaFMvVlo5azlVRHB0ZVFaMWdrSEU5TEN6TzY1azFRRTNENDNRK21ReFM2cGRJL1BpOUUxVkRoN3pMemdpOUVscXFLVHZNYjhPQUxmdSthTStPWlFaUjN4L21UVjQycTNmQlZya2lYRHpNd0pkclhjNW5UcmxLSDJTSUZsV2JaUzNXK0tHUVpoVzJ4dVRzdU9yS1FiVDY2OEVRbEpNTEhuckxLQTFrV0NvalJKV1hqZGFxSGVrWURDWjlFcDZaRnZ4NjJzWlRTdWMrVlNjK3UxSnZjT0w3NTZzNEFFWnNjR3ZnbXNxbUx5MldYOHpLbGw2MEdVUlE0YlBHMHd3YVUxRGF3dnJTejZqTCtyUjVBTTlGdTFlQi9WaUZSVVo4R0prR0VIOTdRWmNKcjV6RFpXNnZkOVBZRnlTd0Zqa21rOWxuZ1NFdFNPZFFITmZTZXRxbXZrcS9HbTB2enlTSWVyM3N5OCszR2IzNjJHaHd5MFNCekp6dEdHM0dQWTE3NUxRK3FWcGJCc1Y0MmgvOExPcnFaUGpVY0RrUk1NMU1LTHBtOEpSeVRGeWM5c0NxZ1lVMzNBbTByRzlkTHgxeVVKaTkwUncxc1pDa0lYUFIxYWFRUlkyNFEyekhVNjNBNHZDQVVaaVBOSHdVZlI4Qzk0cDdDeks5UTlreFpoaGZ6bjRBOFdadVZMSjkvWWI3d1RmNWQvNlNmNVFXWUM2anAvbUVWMDAxRnVBZnUzcUZNNmNuNXpXV2xkR2tjaU5RcUJ3SmZoWk9oUnk1VjBEaW5rMDBjSVlncDFmVnVnWHFkR1grV1ZCQkJ5M29va0toYW05S2RPc1N6aEI4NXZyN3h6R2JsREVXVGhFN0F5U3duRUVVNnBjcXpxR1E3Mk9KLytWS2I4ZVNPVWxzQW1LZnZ0czgzTHBYR2o0dkdRR1UwNVptK2grakdWeEpjMTJSQW5lbUhYK1FiNVhJdGk4ek1CazJkT2I4NUVPRUlvVnduWXpmSmhqQmtpOFhYMUtWaTVWbDE5dmV4OExxQ2pLdW9JeUsrSFpVQWtGMmpqY01WenUybXEvM3JPblJvTUhqVEszbFpGZm53S1E3WUxqd2dlVk45QnBmNm1Zem5Bb1RhVG1kQTUza29ocnMrVExuK0toUEpCRFc3Rml6L0ZDbVhzU2dJQ2tQcHAzVnJnQkY0N1ZDUEtPQi9yR2hPaklKd0V2bjgvZ0o1MU5qSmY3NkI4OUxHKzhLOXZpV2ZCeDRvMGxIczZLRmtCSk5RSTF4TCtVRGREWThURitlNXFtaVg3TTh6QmVsQjJlalZKaW9DRkhUcG9mRlZyT0kzTTlGcUk0Mk9KYVdrQytFTFJCaHR6dmJxaisrMWNOdlArcXVKQkRseTZNY2d3SE5BbzlhOHZIcjNjTmRHdmdjVGNFemx1aHpXOW9wb0dSTERPbHRUT0RqOUNQeUVXU2VablFxV2pHRGZiZkRkWm85bTRTWmUxTjQzNUNZYzJBY2VtR3JDdjAySUhyNmgvR1dZMTRFRlJ6T3crTFQ0Skg2TDBzM2w5V1JlZVlvR2NJc2RxYmhrN1Y0OXF5b1lBKzRlb3IvUi9VRzhZaFFYVzJJckQxaTVveDRGTEtXa0Q1UWtKRWU0VmpyNUVRTTBNTHJzNnE4YW5URklITGV3YXE4V0lnanJLS2FtRWloU2tGK2RnMHdScllTeUpuSzdySUsxWi9GQTlPakFUeGlIN0Y1TWcraGhlbXozYlFrU1FTaGN2T1lVSEdjU2sreHQrMXBuSG1lc1ZZTUlCb2d4S3JkUy9yLy9LM0lxdWR1Wko1bE5oVElXZ3dISkpiTVBHTG9mQUJybTlwZUFCVG5mVUFkcDIxK08wQmluVjdYZVg4RXFmVGhVejhrY2Z0MmgrSW5hajZwd1lDdGJ2MmE4dld5UXFKM0haNnBiZHV3bUJFVzhMa3Y2Qm44Yng5TllZMTdyMDliWDNCbmF6QWpGVW1EN3l6R3pLSnR2c1ZVOUw0RmMyU1B4ZUpQVjluQy91c0ZKc1ZlTEFMMTdqVERyV1k3NXhRdkpDVkJGNFlIS0JHaiszSk5WSWRudElOam5DTWhRak1CZU02V29RRkcyei9IQU9hU1lnaXlJSnlaNzd4MW1UYUtuTkNvSTlzZ3JNZkJzUE9mTXJUbkVGbTR5SThERjFGSTh4VnVONnpBcWp2dGkzNVczRGIzdG9Wa0pYVWk0OStKZzIxRWwxSkNqcjJoVmhBQjN5dE5kV2VnTXlTSFRnY0tRVVdRQmt3WUlEbUphdjY5am9udE9RdWpVbGFIM0lBRExHMUpPSWxuREduN0F2OUhkb0JzdnA3MDdLN20xZmJwOUxZK3NCdkwzcXdNbmpZbGhuZHBmYjdVbGxEajl2SCtuNDE5Z0FWMU9GUkRmVHVkVkRpdEFlQzI5ZWRjSmFGZXBYbmpKeHpvTzNqZHFrVTBiMWRmeEo2T1BCa01XSzJKcDZqTmllVlF6emwzRGJWMnRjcTNpekhQVmRySVZ2eEFqVWl3eENWK1VLTzZmMmlXaG9jQjhsWWE5U2xPOTRxd1Y2SkxSbDlIU3pFbDZtQUdRKzRCaW90aEhleDd2ODlGYnJ3eW00UjkwOGl4cU5odzNCc25wcHkyVzhlQXJtcENxMTRHdjlpM3R4em1mS1c3allIV2xWT0JQZFdoSnQ5NTZWbmliV2pWaVBBME9WOVNRWFZ6L2tpSit1WnZzT0FPY1h0YVRDaTZQL0dDMHJyRmhLc1paQW82ZE5paUF0N1BtVzduQjc5RDU5SzRBd3RNaW5iV016TjRQQzFGcHA5eklQTlEvU0laY1IwN0FjMnJ0ODdoQ0JPNUNIY0xhL2EwZDcxZDNZenEzNFlSWDZRYmdRY2taVytLN0FTbGpUcnFQczBHUXo3eFVRVjY1SnRBUTZvbjBxWGwwQ3drdUFCR0gvVVZ3TXpTalBuSnh5WmhQczN5NFhmdTVOUWhabkQvWWNtenR2Y0tkanBvMExSZzkxZnN3QjQybS8vL282VTd5K1hJNGlXMDMxRFQ0R3ViVWV4NW5mZTByWjdlRTRMaGJkaWJiWVRkTDFESHJuTGhYUVpDaEFRSno5SVV1OWYweEtMY3ovR0lubzRQRC9VK2hKOVkrb3FtelpGM3NhVXpKNTRJY1lGeEVROGo5L25nOTVpWHc0SWM5aXovZmY0Wm9hN2hJMTUzalBMNHFOcS91akphYXd2MXpxRlFhRVJYZUU1UyswZTMwaC9UKzByMmMxMTJkYndZdXljN2UwNi9RVnJpckdSRnQyZnRHUFN2VVRMdTJKVzRBUHVDN1NpNmpYWjQ1QlArenJTNzJteWdQQm9LTSt6N2RYTWMySmhQTnhQcmlGRVJlUmJnQlFFM1RSckpMSVpaR3NPczNJbFdBdGpLRTJaVFd0bjNJQmFQM0loY2sySFJ4MnRXRDJYRnYweTQ1bXhlQnkwMXY0cjAwQjJnMW9JVlYvZkgvajZUQnFLU2VENjBWRGZ3OXMxeXU1VUVhbzRicy9oZmFjWVpZZzg1Y2daS1QrTkZCeHBadG84M3E3bzRBeUNMQTl5dzQ2ZFRzdUlSYnBsMC81MVp0R0hDa29YMkdOa0JRc2pFWTVSNHVoZGRJNnBFSkxuaWNvVnpGS0dsTFErZDJMKy9odnBldHUxMGFTVHhEMmJqWlMrUVlHM0VLZ0VvbDZveThVTHl4bjRMb041bk1zV2d3N0p6NDJWT0V1ZHFENHY0ZVFUdXB0NkRpQzhvRzVzaVdWZER2amZpUHdwN1l5cEFZOE8reFBLOVgzWkU2bVR6aEV6TGxud0Jtc1RuQWpjMTRsYTVha1FBdHJRaXZIY1Vmb1pCcWtQKzFqTmdOZ0lYQlB3WlRBMHh5aEVuYlRMK3JPd3dzcUEycjdMbUlTaFpNa3V0cUQzdC9GbmNBTCtkaTJvQ2pBOVRNdnVwMnRqNm5FaXNwbXpYcmE1WWVnUlVjOE5UNjJxL1dXU25aKy9pb0hUMWFjeldJWG9sN1JhZ0VlQlRlMkFlVVEvam5wd2RwR3gzUldLeGIrajdtN0RuaVpoSmlzZUw5a2JleC9RQUFBV1VxajRBQldtdEptQ1QrUy9KVit6R2FGaU4ybXFzcUd0Mm9qN2w1UzRmMkozcXdxaEpNbXVDRGlteUpzQ0FzOVlNQVFmOXRFRVNSa3pKTy9wOHdEamlFbGRZRUdMNkl2RHJkWHFERzhSTGJkQnczTHJxeUJQOEYwU3lzWmlHYWdXY3BSZGY4NmJKdXgra2gxOXo4eldvSWM4OUVBK2JCVm9ON2M5TEFETEFPbzlYY0pqdllJcFRiWXlJTk1iOVpCRGZlb3d5ZkViZ2Q2bGxiK004MzB5SXFIWVEvaFl0dWpWaDhXazdseG1mMjJzL280eUp3aHNYQlV2OWVWQkFyTDVmbUxPM3NjRmdBejRsR2cvbEN2cThSS0JRaFFYd29CNTM2aDdkRWFnWGxqQk41WGhZcTVmNkZhK0xRRkFIRnlyM2VHT3RZNjJsU3NMUE9Sa2VGQXl6RTY3bk1BZ3lrb1hEUHRrUE9hd2x6bW4zdEVOT3FMMDVRWmEzTkFvZ1RtYVZLYmlUTk1RVVF5M2JQNElYdDE0RlNEa3pweU5pREptcE5yeDJ3cjlVNmJvT08xQTl5eHFMZ1ZHdVNXc1E5Y1ByTm4zV2VZVXJvTjhhZkk4b2w2bFNuODgxaEUrU2I2OU9lZ2UxY09RYUduTUJ4WlpiVThzVDJxd0JsVWFzc0dYWlBOMUU5b3M3UUh5bzJKcmxkU0xrWGpsWWpxV3I2SkJtYmxiRXpRWXg4clA0TDVDUG5RME96WjA0MDV6MklUZXBzSUpHMW90Wng4VmIyWGwvSDNqajNja2F0TUZLU1ZrNTdBQkVIRUp3a3pmbXB4Y3Z0SzBjK081MGpPZUpTOGpJRUhnZUJJSkJTNzRRb0F2VGcvbW5NeTVHVTRGYllHSHZHMDBzYXdBbkNVbW90cm13R2dzcGhkM2orNFNuYm9HZ2Mvd0NzN2FTM0NJcHBBbC8wNTFCbWZhYk8rV2JpRDl4c3dzaElxSjZua3RMSk9mWmM0NjZVZmVpTkVJeG04cU5yQncxTlBrc1lXOWtjK2FtM3diTk1PMVp0N3hIYXU1M01odDVFRExIUjZ6a0wwcGFjY0ZuSndCNXFsS1hSN01Lb3huSmo5VTQyS1FOTFRQditUL2NlNG5oS2dIc2dua00wbU1YelF6Tkx0MDBDdkdGWDRuNnE4Q1JCRnY2SHFSVVdwWGFGdWlrc3Mwa1M3RDc0TThTQ2VnTmRuWit4Z3BLQ0IzOWZWWDEvYmMwUjlDbWN4M050d0hFYXNkZllpUlRIcFI0bGJndG1RUUcrYWNTdVhJWVRaSWFTRzlLWlZVZ3oxeFI4TVhMQXAveDRHbGMzaGNCMURnZ0cybE82RnNBTUhBTDExU3NySk1RUmZsUmxJOU0zNFB0SHRTY2pqSGcwcHRMT3JCOUI4c0NqMEk5bG1aWHU4cW1pMEQzMmg2VC96MnRvOFJMcmExVldZblp5NW9nYmhiQ2E4Sk5JZmNGQmJDTytpUXZlN2xGQ0RXZGJncDZJallGcXR4amdGUmkzVURaMExtQjVqSk9lejA1VWRNT3c3SjFudkhvSDM3RGZFclE5VWZKeUlpRjdGNzR4c2ZMSFIxSXpGenB6YnIyM2QwU3c5OXlCNjlDa1ZtdERCaXo3aWFmaVpXYzBZU2svajkrWDR4NENwU1diOVRMRTY5djI1MStjS0xzZzRPT2ppUHVSYTRnL25oaFB6eGN5bGE4WjNYb2s1ZTdJRy9BbWtCNkEvL29pRFdEKzBzbXJGOUI4VlNnVENiRHRNdFNyUStGUVBzZHBMdG52UndOY0pGcHJEaVVHN25FUTdMQnhoZHhraTZ3dXRuTnY1b2dsUkdheHV4Tk9XYXZaNGUxOTVEaXlVQkN4cjM5MlRjUkxKNExIOE1rTUpnNml2dmlNYllqeTBwSVpLVGJGSjRzOXZ6WlFwVjZVd1FlWEM0TGRWd1E2dlltb05Mb2JCaUlsSE9hUUUxM1hpTEliVTU2aEJVRnJqSHhiNzNRUm1SQ1poeWZpVUNSdUg4YWZjOEpyMFFkMXlJYTJNczd4bU9FczlCWmFwejdTR01OeURXUXlIY0Q5VzgvQ0d1OFlhUldRaWlBQTU4MDRlQWF6MmJnYUNuR0wrNHdZeXpYOXNvWnVGWFZ2eklDbVk3bVF5c1pVMllqUVZoRjdHZWFGTDNKL2ZGTTdqOVdiaThjZG1MNzJENGdLVDVXUmpKTGNVY01HNHNXZTJoNkJncWVybDNJeDFmMzRteGZOSUpFVnlLTTVzVW54a0kvTTFORDU5M2g0UWJGYWVUTjZkc2NLenRrK084OW82Rnhma1dvUFZYRlZJTmF0WFhoSVJHU0cvKzhSQXNNYi81QUZMb0Y5U2x6YytXaWkxQkQ5RGhwZFQvd01ya0lDUWdzVklMbUt4bnhobXZhS3pvcGEyaG9GdXBiL3A2Z2hMQVZpY2RROHZJa3Y4U0hBeGZJc0sxaFZXcHNRMUl0SGw5N3lnSHNtQ0lkR1NJcVNiaGwzdW9CNXhWWWVGV0FObXpYQ3g0OE5oTlc2SnNHZ1c5RXp1NjdlY2Z3VUZlUEZpYXpvbWFPUTFRc3ZjYVhHVGIxWjA0UzdQay9OZmlCWWFJSkoxbGlIMnBaeDhMZGZwZTVuRENtbTlYTVZHbUY2SVdWVjM0QW1uK1B5TlNCcWxzZDZyQlNjWVRISm43ZElUZm9Zd3JvZjZvNVBUR2lwUHNlYXNHbDJoWFpCMWRYc1U0aTJKVDNLenVTeUl1RVU2Y2Z5M242T3duNmNjV0NyUFNLc3Vwb2Z0QithenZpZzd0bUFvRHlFTHN4eUE1dzQrZ0RmQm1BeStwNG02NnVNWjFUWEJiSTZhZ2RzVEpteUtHMm1NNFZrUmo0Z1cvcW0yMDNISno0YlVJN2dlcXNHQktNbGdPR1ZHRDRGZGlPaWxPbkNxeGo5NmFiY0Q5SnVmeVJUYUFmSC9QbGJaaU5mOTVORWtxaXZmNC9CN2lqaEdIZlUwcXFNblJlYVdackFuK2M3RlByc2h6UWIrMC9OUSt1dWRMbGJ6czZHd1IyUG5sNmlNdjRsUFZ3d1UyTWprYzdMUzY5ZzZpSnBZZytsbDM1N0toSWhPUTRpMkNzVXhXWHlVZy9VZCtaQmhSTDFhWWxWQ1NaK1VRZlJodVNCREdkLzNrYjR0azNvUVMzaVgrS09EVFB5RGwxaTUweXhZdjJQZjRPdG1QR1RVYkdUeUJQd1RPUGN4TUR5dDBjWjAzdVdtY0MwblVrMllnWnlLeFFXTTBSaHJVK2pRUVZwL1BWY1NRdGYwREtTSDZzUEh2M1RlbmJMV25sdzNKaUlveEhmRjRJTGZhY255M0xPTGFxcXN1QU95REJmMnQxdlF2UTdkMmtZMGhwdUF4Y091c0I4dXpmdmQyTWtramZwVHFNWGN4TndNbUxWYXRobGVpQUUwRVBFaTFDanZuWVgyQUE5a2pwLy9oRlZaaklvK0ZYRzlQRE5ObVdDTVRPSXQwcmZoRzFxNTFDbG1sQW41Mm1vQ016d0lNOGlLVXk0MDNPdElBQkgrSzhTbHQ4aFpEaHRmRDBoR0xVOXg0TVBaUmhxMmdRd0tCL3Fpd3BnVnNWbDhrNmVxUnZpMjFjeWFJRklIRVQ3L0ljT25zWU1rYnh2azBQdGtIL0VUSHhsQjVqMUJ6TmJhQ0hJZ291bWJwVDdadlEyWjRESFhXNXJQdU55YVN6MEF2bTZ3dHljMDVxVTJVbXRWMXFOL1NOb203SkFkbms5ajg1TFUydUh1bVdqZHNLbVdFNXFLdWprcW16N3pEOE8yVGhuVzc3SWZQRngveG8yWXlaZUU2OXRFVlJCZ0dHUFA3R1NyaTVMaUl2TzZwTkZMak96QnRJTERnMUxFQUo1VUlqNjd4U0VzUjRIRW9CVEM1NHZKSUFoLzMxak0vUE96VFdkZ01YcXhlSlhGenE3ZHRqTWcrLzNSY0hIVm9LRGd3NjlrMmNnYXpwRzIwdVZuMTZkUUJYN0Jpdk12TVc3OStUb0xPcm0ydXhrN0VtUkNTVFUzMlFBbVZ6Z09mZHRKUDF2TWk0SU93aDVSYW51YWh2ekhIWDNHR3pRTkx4a1RiUXFFUjZmaHV0cEVVcEFOWmVMbnA2UzVaMkIwZGtVZ1BSeGc2NUpXY05OS1BSc0NrWkkxK1NTU1haeVMrOWFrUzhtd3c0NXRzdHRaTlZSR003RVh4YjUrU0FkMkwybFpLbnlNRll1M2lSZWcrSnZtMUIxVFZRL3lKejY0MFlLUzNMYitIQ3hoSmhTTGlhYk5Kb1Y3V1VuZTBGekt6bXVDdGRtR3BIWkM5cXh1SGdDcHRuVTJVb2oxNWF6Y2dBWHAyZjF6OHVUVCs2dXpxTm5lOVdzUHlwdE9NdlFhNDJzdmtZNlU5TkcvSi9VUTdRRmUrL2VUNnp6ZGQ2a2lSNzA1ZXBVeTA5MkpIekQrOWJDMmxtYWk4RGo0U3o0MVhUWmEvTHYzdXQwOTk1L3ptb3Z1R2M2VTdXMmFTSG9LcUs4dXRKeEliVmtKb3hYbFFuckVIMlM1YXc3WG1lREtwbzVwYXlLTU56eXhJeGxoTmxsRUVqbVdnODFBajRLbmFsOUR3N09sVVhrWE02eWFqWjNqaUN2Uk9RQVRVbGVid2gzWFppTnJtc1J4b3lWMVg5OWEzaWN1THlpRUJBVkRYQ0kwcTJqYWdCc1h4L3Nrci9oa2lhYkZqSCs3MUVvVWVjRm11RmhvcGxMak1td0tsSWFwTk02NENUaGRpdGdoUklUTFVDb2ZGYUQxOHd6bldlaEZrSFlVUW1JWXRFdzJYb005V2FMN1Fod0ZoeHVhL3FScFRLUTMxOXBNWk1qN2UrMlhaYk93Y0VLYnE2MFhRSllHaDNGMTUxSENYVW9lRHY1Nm42Yk52ckU2YVdkdkFEa3F1RWw3RTNYSmdueTlXOVJCSnMvMEo4QkxjNnlPOWk3V3ZIVVFwN3JRZkhGWklMbEIwSHgrcXhVWG1LWG5KZTczcGhSY0tTNjVIb3d4WjYreHppclFHTXhtci85R05VUEd5TVROR1ArRGlKbW1La3FMT09jd0NFSFNuZnl1NmExN24rM1l3U1g5NitNbkVmdTIwckhPb1pqVVZuT1ptRkNFRFFYZ0s3NWR5b3BzclZlM0pLZHBmYVFOVDllT0dvNk1qZDNiS3UrTVZDR3g4TitrNWE3ajJ3cGxtTVhuTVB6Q1JmcEkzd1pQeTRQc1VhVTEyS2xvaUZFT3poZTJGMk9EYUwxU3lGY2RueWhyRTgvcnZSc3pVV2R3UjZEai9LaVh0OC9vSm5aY2R5bDdjKzZSNi9HenRlSHZqY0oya1BnUk9nTURpUDFlTmVkNzJ0UmtzQjllNXZsczNZRnNrNWlBa1hiNEw5MjRibGx6c1VXQXBCeFRkMXFLS1hYZzhQVFhqanNCYTQ5dnNBNUVvaFZmbUUwMnR2NHNjQkZMaU5VcXdZY0dxZ25KbEFQQ3FaOGdnT1E3VnhWZFZuMVlRZkJPMm1vVGdaU0wrQ0NUeE9qRXlwSkR2RnM5Z01JZ0l3V0hBSFhNOGdQanZucXBsN1d3bXh0a2l3aUdEU1V6bjFscHViTEV2czdxYWxNZ2hieXVuVzRlcU5WdlBmUmlNMlllSGhheUF6dFF5MXFXaTJ6cGg1VWExWjFKQVREaW9FanBFMHNTN0FlZEdPNmovVzFmZDV6R1pibHlIN1M5VDY2ZEU0OHRjaFo0R0YxVmsvZlFYSGRRT0lkb1pabUE1T05yS0FuQWVWOEh2QUFxa29Nd3J4ZGFXN1lYMWNHSitXTUdOR08xU0VLVWczMldmUG1pY1hLTG9JWDBEUW1OYmd3TjNFenVtMm1uNjNNUTN2amVqckVaRnpsUmhKbStDYVMwTGJxVDVIRkRWWVBOb2xOZjl3aEFxMzAvSFZaaWt6UHhWM3lJQmlrdmE1QTFuSmZWcFhZRXFNa2IvaDR0V05iNXN3U2pucUVEOHViOU5Pc3RIcmVZaE9RYnBLelVHU2RjTkF1K1IrVDJzUlJBQzQ2TlZadmZOcVZ5UU90YVh0czhRdzRXdEJCaXpKS0xtLzBYd1oxMXdNZmtqci9nckg0cmllRGEwZTd1S2tQV3pZOXJqc2lpQ2MwL1ozUjBIM1hLNTVTOTB1bjVIVitRbkt1eHlyYk03UGhFUXVnRVE2TlQ3cVhvV1U1b3BSL1p2NmloSEhYMzB1ZStFYW53SmdlUUN4WGpsTlZEUGY2WEpFNXQ4eWxLMFd5andOQWZpdzdiZ2F3MVk5YVU1MU5ZZUc3QXo5RldXSWhHVGpmSXZMMThVY0pQWndib1hqNHZHMkdyc01YRDNMUjFKV2xJZGIwL29uTndvOENZYncrOFlhc3RtOUw0dzlDQUQzTHZRVzBBQ3dkS3hMQ1NycW5UWmw0YStTbHUvNXFTN2RIdzlBSGpMVnFFRGtLWU9qNnFEVHdpTWFzNkR4bEt0RmxXa2wyaWZFaFl0UGVERmg5d2ZOdHFhUjdBRFZtcWQyL3p0aFpzcmlaTVpvdmluMlJSWGptSTZsRGRkMFhScFhNV2hWQkUrN1JKZ0VRZTNzV28yS3d2TUtZMS9PcWVXYkxndUZZSVZTZ0w4NkFTU3g8L3hlbmM6Q2lwaGVyVmFsdWU%2BPC94ZW5jOkNpcGhlckRhdGE%2BPC94ZW5jOkVuY3J5cHRlZERhdGE%2BPC9zYW1sMjpFbmNyeXB0ZWRBc3NlcnRpb24%2BPC9zYW1sMnA6UmVzcG9uc2U%2B
\ No newline at end of file
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://example.none/auth/complete/tpa-saml/" ID="_a07fd9a0848373e55320dc342494ef5d" InResponseTo="TESTID" IssueInstant="2015-06-15T00:07:15.188Z" Version="2.0"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://idp.testshib.org/idp/shibboleth</saml2:Issuer><saml2p:Status><saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></saml2p:Status><saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_302d198c26a82fda79326d40c9237bc0" IssueInstant="2015-06-15T00:07:15.188Z" Version="2.0"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://idp.testshib.org/idp/shibboleth</saml2: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="#_302d198c26a82fda79326d40c9237bc0"><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#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>DCu+i7m7i+AmlzMmsqSLMvjjMiRi6r9ocGsGymCTRj0=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>UJahwzSLB/I8S3zqwqnn+NxR5gYcZ+QqAwn7CDxuTcsGt2XzNH7OXuzWRjInSRaQy/Wl2gOFGRKITiVBuv4FLetA9u1S7MAB10o8Y5NkHtKQqB0nqCt/FkJnfYVcx1j3LS11vtvggQm9Dahfmxglv4B3lM3JHdy0/EKgE1H9QPQ0040Ii28IHWOj6KjjY/hSBdxvq8t/EM6WN0B10e7YFVZ1xoVXuKn6GHIRGMYVXTlkTSVm6e+BadB1YNAIkw4bEulKO0af52qxS8JcL9kbsLW6kRIBQj43ZXjuOK7xgCBlfzYM4wYA+jVQBiKAJDHAiUFd1NAqWgMkrbwzWSJjJw==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEVMBMGA1UECBMM
UGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYDVQQKEwhUZXN0U2hpYjEZMBcG
A1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcx
CzAJBgNVBAYTAlVTMRUwEwYDVQQIEwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gx
ETAPBgNVBAoTCFRlc3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7CyVTDClcp
u93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe3OQ01Ow3yT4I+Wdg1tsT
pSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aTNPFmDixzUjoYzbGDrtAyCqA8f9CN2txI
fJnpHE6q6CmKcoLADS4UrNPlhHSzd614kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB
5/9nb0yh/ojRuJGmgMWHgWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HE
MIHBMB0GA1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ869nh8
3KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBlbm5zeWx2YW5pYTET
MBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNoaWIxGTAXBgNVBAMTEGlkcC50ZXN0
c2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5M
FfSVk98t3CT9jHZoYxd8QMRLI4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpk
OAvZZUosVkUo93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4
/SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAjGeka8nz8Jjwx
pUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr8K/qhmFT2nIQi538n6rVYLeW
j8Bbnl+ev0peYzxFyF5sQA==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" NameQualifier="https://idp.testshib.org/idp/shibboleth">_37f8251113491e2cd666495938ccf270</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData Address="70.36.54.223" InResponseTo="TESTID" NotOnOrAfter="2015-06-15T00:12:15.188Z" Recipient="http://example.none/auth/complete/tpa-saml/"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2015-06-15T00:07:15.188Z" NotOnOrAfter="2015-06-15T00:12:15.188Z"><saml2:AudienceRestriction><saml2:Audience>https://saml.example.none</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2015-06-15T00:07:14.939Z" SessionIndex="_6302f91a5c4c51987d814d16002480d2"><saml2:SubjectLocality Address="70.36.54.223"/><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement><saml2:AttributeStatement><saml2:Attribute FriendlyName="uid" Name="urn:oid:0.9.2342.19200300.100.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">myself</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="eduPersonAffiliation" Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Member</saml2:AttributeValue><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Staff</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="eduPersonPrincipalName" Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">myself@testshib.org</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="sn" Name="urn:oid:2.5.4.4" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">And I</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="eduPersonScopedAffiliation" Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.9" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Member@testshib.org</saml2:AttributeValue><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Staff@testshib.org</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="givenName" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Me Myself</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="eduPersonEntitlement" Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.7" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">urn:mace:dir:entitlement:common-lib-terms</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="cn" Name="urn:oid:2.5.4.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Me Myself And I</saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="eduPersonTargetedID" Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue><saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" NameQualifier="https://idp.testshib.org/idp/shibboleth" SPNameQualifier="https://saml.example.none">uJ4gM4NoVMUAwfe16VxPYEVyfj0=</saml2:NameID></saml2:AttributeValue></saml2:Attribute><saml2:Attribute FriendlyName="telephoneNumber" Name="urn:oid:2.5.4.20" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">555-5555</saml2:AttributeValue></saml2:Attribute></saml2:AttributeStatement></saml2:Assertion></saml2p:Response>
\ No newline at end of file
......@@ -4,6 +4,7 @@ Third_party_auth integration tests using a mock version of the TestShib provider
import datetime
import json
import logging
import os
import unittest
from unittest import skip
......@@ -25,7 +26,7 @@ from openedx.features.enterprise_support.tests.factories import EnterpriseCustom
from third_party_auth import pipeline
from third_party_auth.saml import SapSuccessFactorsIdentityProvider, log as saml_log
from third_party_auth.tasks import fetch_saml_metadata
from third_party_auth.tests import testutil
from third_party_auth.tests import testutil, utils
from .base import IntegrationTestMixin
......@@ -124,10 +125,15 @@ class SamlIntegrationTestUtilities(object):
""" Mocked: the user logs in to TestShib and then gets redirected back """
# The SAML provider (TestShib) will authenticate the user, then get the browser to POST a response:
self.assertTrue(provider_redirect_url.startswith(TESTSHIB_SSO_URL))
saml_response_xml = utils.read_and_pre_process_xml(
os.path.join(os.path.dirname(os.path.dirname(__file__)), 'data', 'testshib_saml_response.xml')
)
return self.client.post(
self.complete_url,
content_type='application/x-www-form-urlencoded',
data=self.read_data_file('testshib_response.txt'),
data=utils.prepare_saml_response_from_xml(saml_response_xml),
)
......@@ -488,6 +494,57 @@ class SuccessFactorsIntegrationTest(SamlIntegrationTestUtilities, IntegrationTes
)
self._test_register(country=expected_country)
def test_register_sapsf_with_value_default(self):
"""
Configure the provider such that it can talk to a mocked-out version of the SAP SuccessFactors
API, and ensure that the data it gets that way gets passed to the registration form.
Check that value mappings overrides work in cases where we override a value other than
what we're looking for, and when an empty override is provided it should use the default value
provided by the configuration.
"""
# Mock the call to the SAP SuccessFactors OData user endpoint
ODATA_USER_URL = (
'http://api.successfactors.com/odata/v2/User(userId=\'myself\')'
'?$select=username,firstName,country,lastName,defaultFullName,email'
)
def user_callback(request, _uri, headers):
auth_header = request.headers.get('Authorization')
self.assertEqual(auth_header, 'Bearer faketoken')
return (
200,
headers,
json.dumps({
'd': {
'username': 'jsmith',
'firstName': 'John',
'lastName': 'Smith',
'defaultFullName': 'John Smith',
'country': 'Australia'
}
})
)
httpretty.register_uri(httpretty.GET, ODATA_USER_URL, content_type='application/json', body=user_callback)
provider_settings = {
'sapsf_oauth_root_url': 'http://successfactors.com/oauth/',
'sapsf_private_key': 'fake_private_key_here',
'odata_api_root_url': 'http://api.successfactors.com/odata/v2/',
'odata_company_id': 'NCC1701D',
'odata_client_id': 'TatVotSEiCMteSNWtSOnLanCtBGwNhGB',
}
self._configure_testshib_provider(
identity_provider_type='sap_success_factors',
metadata_source=TESTSHIB_METADATA_URL,
other_settings=json.dumps(provider_settings),
default_email='default@testshib.org'
)
self.USER_EMAIL = 'default@testshib.org'
self._test_register()
@patch.dict('django.conf.settings.REGISTRATION_EXTRA_FIELDS', country='optional')
def test_register_sapsf_metadata_present_override_relevant_value(self):
"""
......
"""Common utility for testing third party oauth2 features."""
import json
from base64 import b64encode
import httpretty
from onelogin.saml2.utils import OneLogin_Saml2_Utils
from provider.constants import PUBLIC
from provider.oauth2.models import Client
from social_core.backends.facebook import FacebookOAuth2, API_VERSION as FACEBOOK_API_VERSION
......@@ -96,3 +99,42 @@ class ThirdPartyOAuthTestMixinGoogle(object):
USER_URL = "https://www.googleapis.com/plus/v1/people/me"
# In google-oauth2 responses, the "email" field is used as the user's identifier
UID_FIELD = "email"
def read_and_pre_process_xml(file_name):
"""
Read XML file with the name specified in the argument and pre process the xml so that it can be parsed.
Pre Processing removes line retune characters (i.e. "\n").
Arguments:
file_name (str): Name of the XML file.
Returns:
(str): Pre Processed contents of the file.
"""
with open(file_name, 'r') as xml_file:
return xml_file.read().replace('\n', '')
def prepare_saml_response_from_xml(xml, relay_state='testshib'):
"""
Pre Process XML so that it can be used as a SAML Response coming from SAML IdP.
This method will perform the following operations on the XML in given order
1. base64 encode XML.
2. URL encode the base64 encoded data.
Arguments:
xml (string): XML data
relay_state (string): Relay State of the SAML Response
Returns:
(str): Base64 and URL encoded XML.
"""
b64encoded_xml = b64encode(xml)
return 'RelayState={relay_state}&SAMLResponse={saml_response}'.format(
relay_state=OneLogin_Saml2_Utils.case_sensitive_urlencode(relay_state),
saml_response=OneLogin_Saml2_Utils.case_sensitive_urlencode(b64encoded_xml)
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment