92 |
92 |
(saml2utils.Saml2Metadata.SINGLE_LOGOUT_SERVICE,
|
93 |
93 |
soap_bindings, '/slo/soap'),
|
94 |
94 |
(saml2utils.Saml2Metadata.ARTIFACT_RESOLUTION_SERVICE,
|
95 |
|
lasso.SAML2_METADATA_BINDING_SOAP, '/artifact')
|
|
95 |
lasso.SAML2_METADATA_BINDING_SOAP, '/artifact'),
|
|
96 |
(saml2utils.Saml2Metadata.MANAGE_NAME_ID_SERVICE,
|
|
97 |
soap_bindings+asynchronous_bindings, '/name_id_management'),
|
96 |
98 |
)
|
97 |
99 |
metadata_options = {'key': settings.SAML_SIGNATURE_PUBLIC_KEY}
|
98 |
100 |
|
... | ... | |
1641 |
1643 |
logger.warning('failure, expected: %r got: %r ' \
|
1642 |
1644 |
% (destination, req_or_res.destination))
|
1643 |
1645 |
return result
|
|
1646 |
|
|
1647 |
class NoLogger(object):
|
|
1648 |
def error(self, *args, **kwargs):
|
|
1649 |
pass
|
|
1650 |
def warning(self, *args, **kwargs):
|
|
1651 |
pass
|
|
1652 |
def info(self, *args, **kwargs):
|
|
1653 |
pass
|
|
1654 |
def critical(self, *args, **kwargs):
|
|
1655 |
pass
|
|
1656 |
def debug(self, *args, **kwargs):
|
|
1657 |
pass
|
|
1658 |
|
|
1659 |
class RequestProcessing(object):
|
|
1660 |
def __init__(self, request, profile_name, request_method, logger):
|
|
1661 |
self.profile_name = profile_name
|
|
1662 |
self.request_method = request_method
|
|
1663 |
self.logger = logger or NoLogger()
|
|
1664 |
self.id = 'request-id-unknown'
|
|
1665 |
|
|
1666 |
def log(self, fn, message, args, kwargs):
|
|
1667 |
fn('[%s] %s: %s' % (self.id, self.profile_name, message), *args, **kwargs)
|
|
1668 |
|
|
1669 |
def info(self, *args, **kwargs):
|
|
1670 |
self.log(self.logger.info, args[0], args[1:], kwargs)
|
|
1671 |
|
|
1672 |
def debug(self, *args, **kwargs):
|
|
1673 |
self.log(self.logger.debug, args[0], args[1:], kwargs)
|
|
1674 |
|
|
1675 |
def error(self, *args, **kwargs):
|
|
1676 |
self.log(self.logger.error, args[0], args[1:], kwargs)
|
|
1677 |
|
|
1678 |
def load_provider(self):
|
|
1679 |
remote_provider_id = self.profile.remoteProviderId
|
|
1680 |
self.info('loading provider %s', remote_provider_id)
|
|
1681 |
self.provider = load_provider(self.request, remote_provider_id, server=self.server)
|
|
1682 |
if not self.provider:
|
|
1683 |
self.error('unknown provider')
|
|
1684 |
return False
|
|
1685 |
return True
|
|
1686 |
|
|
1687 |
def error_response(self, code, requester=True):
|
|
1688 |
# build an error response, and return it
|
|
1689 |
self.info('returning status code %s', code)
|
|
1690 |
return 'not done'
|
|
1691 |
|
|
1692 |
def set_id(self):
|
|
1693 |
if self.profile.request and self.profile.request.id:
|
|
1694 |
self.id = '[%s]' % self.profile.request.id
|
|
1695 |
|
|
1696 |
def call_process_request(self, provider_loaded=False):
|
|
1697 |
try:
|
|
1698 |
getattr(profile, request_method)(message)
|
|
1699 |
except (lasso.ServerProviderNotFoundError, lasso.ProfileUnknownProviderError):
|
|
1700 |
self.set_id()
|
|
1701 |
if not provider_loaded:
|
|
1702 |
if self.load_provider():
|
|
1703 |
return self.call_process_request(self, True)
|
|
1704 |
return self.error_response(AUTHENTIC_STATUS_CODE_UNKNOWN_PROVIDER)
|
|
1705 |
except lasso.DsError:
|
|
1706 |
self.set_id()
|
|
1707 |
self.error('signature error', self.id)
|
|
1708 |
return self.error_response(lasso.LIB_STATUS_CODE_INVALID_SIGNATURE)
|
|
1709 |
except lasso.Error, e:
|
|
1710 |
self.set_id()
|
|
1711 |
self.error('lasso error on processing: %s', lasso.strError(e.code))
|
|
1712 |
return self.error_response(None)
|
|
1713 |
self.set_id()
|
|
1714 |
self.info('request processed')
|
|
1715 |
return None
|
|
1716 |
|
|
1717 |
def __call__(self, request):
|
|
1718 |
self.request = request
|
|
1719 |
self.logger.info('start processing request for %s', self.profile_name)
|
|
1720 |
self.server = create_server(self.request)
|
|
1721 |
self.profile = getattr(lasso, object_name)(server)
|
|
1722 |
if request.method == 'POST':
|
|
1723 |
# POST
|
|
1724 |
if lasso.SAML2_FIELD_REQUEST in request.POST:
|
|
1725 |
message = request.POST[lasso.SAML2_FIELD_REQUEST]
|
|
1726 |
self.method = lasso.HTTP_METHOD_POST
|
|
1727 |
else: # SOAP
|
|
1728 |
message = get_soap_message(request)
|
|
1729 |
self.method = lasso.HTTP_METHOD_SOAP
|
|
1730 |
elif request.method == 'GET':
|
|
1731 |
message = request.META['QUERY_STRING']
|
|
1732 |
self.method = lasso.HTTP_METHOD_REDIRECT
|
|
1733 |
self.call_process_request()
|
|
1734 |
|
|
1735 |
def validate(self, request):
|
|
1736 |
try:
|
|
1737 |
self.profile.validate_request()
|
|
1738 |
except lasso.Error, e:
|
|
1739 |
self.error('lasso error on validation: %s', lasso.strError(e.code))
|
|
1740 |
return self.error_response(None)
|
|
1741 |
return None
|
|
1742 |
|
|
1743 |
def name_id_management(request):
|
|
1744 |
'''Handle samlp2:NameIDManagementRequest messages'''
|
|
1745 |
request_process = RequestProcessing('NameIdManagement', 'process_request_msg')
|
|
1746 |
premature_response = request_process(request)
|
|
1747 |
if premature_response:
|
|
1748 |
return premature_response
|
|
1749 |
load_federation(request, request_process.profile)
|
|
1750 |
premature_response = request_process.validate(request)
|
|
1751 |
if premature_response:
|
|
1752 |
return premature_response
|
|
1753 |
save_federation(request, request_process.profile)
|
|
1754 |
if request_process.profile.request.Terminate:
|
|
1755 |
request_process.info('request to terminate federation')
|
|
1756 |
# search all federation of current user with provider, and erase them
|
|
1757 |
q = LibertyFederation.objects.filter(
|
|
1758 |
sp_id=request_process.provider.entity_id)
|
|
1759 |
count = q.count()
|
|
1760 |
q.delete()
|
|
1761 |
if count:
|
|
1762 |
request_process.info('deleted %d federation', count)
|
|
1763 |
else:
|
|
1764 |
request_process.info('no federation found to delete')
|
|
1765 |
else:
|
|
1766 |
True
|
|
1767 |
|
|
1768 |
def name_id_management_idp_response(request, profile=None, next_url=None,
|
|
1769 |
response=None):
|
|
1770 |
if not profile:
|
|
1771 |
next_url, provider
|
|
1772 |
|
|
1773 |
def name_id_management_idp(request):
|
|
1774 |
'''Initiate a samlp2:NameIDManagementRequest, some parameters can be passed
|
|
1775 |
to the method:
|
|
1776 |
- provider_id: the entity ID of the targetted provider (required)
|
|
1777 |
- terminate: if present means that we want to terminate the current
|
|
1778 |
federation with the provider.
|
|
1779 |
- new_name_id: if terminate is absent, give the name of the new
|
|
1780 |
federation to create with the provider.
|
|
1781 |
- http_method: an integer giving the http method to use (see Lasso for
|
|
1782 |
the integer values) (optional). If absent the first declared
|
|
1783 |
http_method in the metadata file is used.
|
|
1784 |
- next_url: a return URL, default from settings used if absent
|
|
1785 |
(optional)
|
|
1786 |
'''
|
|
1787 |
if 'SAMLResponse' in request.GET or 'SAMLResponse' in request.POST:
|
|
1788 |
return name_id_management_idp_response(request,
|
|
1789 |
response=request.POST.get('SAMLResponse') or
|
|
1790 |
request.META['QUERY_STRING'])
|
|
1791 |
elif request.method != 'POST':
|
|
1792 |
return HttpResponseBadRequest('Only the POST method is supported')
|
|
1793 |
try:
|
|
1794 |
provider_id = request.POST['provider_id']
|
|
1795 |
except KeyError:
|
|
1796 |
return HttpResponseBadRequest('Missing provider_id parameter')
|
|
1797 |
server = create_server(request)
|
|
1798 |
provider = load_provider(request, provider_id, server=server)
|
|
1799 |
if not provider:
|
|
1800 |
return HttpResponseBadRequest('Unknown provider')
|
|
1801 |
http_method = server.getProvider(provider_id) \
|
|
1802 |
.getFirstHttpMethod(server, lasso.MD_PROTOCOL_TYPE_MANAGE_NAME_ID)
|
|
1803 |
if not http_method:
|
|
1804 |
return HttpResponseBadRequest('No HTTP method available')
|
|
1805 |
next_url = request.POST.get('next_url', settings.LOGIN_REDIRECT_URL)
|
|
1806 |
if 'http_method' in request.POST:
|
|
1807 |
try:
|
|
1808 |
passed_http_method = int(request.POST['http_method'])
|
|
1809 |
if lasso.HTTP_METHOD_NONE < passed_http_method < lasso.HTTP_METHOD_LAST:
|
|
1810 |
http_method = passed_http_method
|
|
1811 |
except ValueError:
|
|
1812 |
pass
|
|
1813 |
terminate = 'terminate' in request.POST
|
|
1814 |
if not terminate:
|
|
1815 |
if 'new_name_id' not in request.POST:
|
|
1816 |
return HttpResponseBadRequest('Missing new_name_id parameter')
|
|
1817 |
new_name_id = request.POST['new_name_id']
|
|
1818 |
else:
|
|
1819 |
new_name_id = None
|
|
1820 |
profile = lasso.NameIdManagement(server)
|
|
1821 |
load_federation(request, profile)
|
|
1822 |
try:
|
|
1823 |
profile.initRequest(provider_id, new_name_id, http_method)
|
|
1824 |
except lasso.Error, e:
|
|
1825 |
raise
|
|
1826 |
if profile.msgBody and profile.msgUrl: # SOAP
|
|
1827 |
try:
|
|
1828 |
soap_response = send_soap_request
|
|
1829 |
except Exception, e:
|
|
1830 |
raise
|
|
1831 |
return name_id_management_idp(request, response=soap_response,
|
|
1832 |
profile=profile, next_url=next_url)
|
|
1833 |
else:
|
|
1834 |
save_key_values(profile.request.id, next_url, provider_id)
|
|
1835 |
return return_saml2_request(request, provider_id, profile)
|
|
1836 |
|
|
1837 |
|
|
1838 |
urlpatterns = patterns('',
|
|
1839 |
(r'^metadata$', metadata),
|
|
1840 |
(r'^sso$', sso),
|
|
1841 |
(r'^continue$', continue_sso),
|
|
1842 |
(r'^slo$', slo),
|
|
1843 |
(r'^slo/soap$', slo_soap),
|
|
1844 |
(r'^idp_slo/(.*)$', idp_slo),
|
|
1845 |
(r'^slo_return$', slo_return),
|
|
1846 |
(r'^finish_slo$', finish_slo),
|
|
1847 |
(r'^artifact$', artifact),
|
|
1848 |
(r'^idp_sso/(.*)$', idp_sso),
|
|
1849 |
(r'^idp_sso/([^/]*)/([^/]*)$', idp_sso),
|
|
1850 |
(r'^idp_sso/([^/]*)/([^/]*)/([^/]*)$', idp_sso),
|
|
1851 |
)
|