第一步安装signxml、BeautifulSoup(3.2.1)模块
from signxml import XMLVerifier from BeautifulSoup import BeautifulStoneSoup from django.contrib.auth import authenticate def get_sso_response(request): data = request.POST.get('SAMLResponse', None) assertion = base64.b64decode(data) try: huaweicertpath = sso_setting.IDP_CERT_FILE x509certcontent = open(huaweicertpath, 'rt').read() verified_data = XMLVerifier().verify(assertion, x509_cert=x509certcontent).signed_xml except Exception as e: logger.error('验证失败') logger.error(traceback.format_exc()) error = 'SSO登录失败' return render(request, 'login.html', {'error': error}) attributes = _get_attributes_from_assertion(assertion) user = _get_user_from_assertion(assertion, attributes) (returncode, returnmsg) = validateResponse(assertion) if returncode != 1: return render(request, 'login.html', {'error': returnmsg}) user = authenticate(username=user.username, token=CRYPTOR.gen_rand_pass(16)) if user is None: raise Exception('Unable to login user "%s" with SAML2SP_SAML_USER_PASSWORD' % user.email) login(request, user) if user.role == 'SU': request.session['role_id'] = 2 elif user.role == 'GA': request.session['role_id'] = 1 else: request.session['role_id'] = 0 return HttpResponseRedirect(reverse('index')) def _get_attributes_from_assertion(assertion): """ Returns the SAML Attributes (if any) that are present in the assertion. NOTE: Technically, attribute values could be any XML structure. But for now, just assume a single string value. """ attributes = {} soup = BeautifulStoneSoup(assertion) attrs = soup.findAll('saml:attribute') for attr in attrs: name = attr['name'] values = attr.findAll('saml:attributevalue') if len(values) == 0: # Ignore empty-valued attributes. (I think these are not allowed.) continue elif len(values) == 1: # See NOTE: attributes[name] = values[0].string else: # It has multiple values. for value in values: # See NOTE: attributes.setdefault(name, []).append(value.string) return attributes def validateResponse(rawxml): current_date = datetime.datetime.utcnow() valid_from = _get_valid_start_from_assertion(rawxml) valid_until = _get_valid_end_from_assertion(rawxml) valid_from_date = datetime.datetime.strptime(valid_from, '%Y-%m-%dT%H:%M:%SZ') valid_until_date = datetime.datetime.strptime(valid_until, '%Y-%m-%dT%H:%M:%SZ') if 'www.huawei.com' != _get_saml_issuer_from_assertion(rawxml).lower(): return (-1, 'saml issuer error') elif current_date.date() < valid_from_date.date(): return (-2, 'not valid before ' + valid_from_date.strftime("%Y-%m-%d %H:%M:%S")) elif current_date.date() > valid_until_date.date(): return (-3, 'not valid after ' + valid_until_date.strftime("%Y-%m-%d %H:%M:%S")) else: return (1, 'ok') def get_saml_requst(request): lines = sso_setting.SSO_REQUEST_TEMPLATE keycontent = open(sso_setting.SSO_KEY, 'rt').read() certcontent = open(sso_setting.SSO_CERT, 'rt').read() requestcontent = base64.encodestring(get_saml_request_content(keycontent, certcontent, lines)) next = '' request_url = sso_setting.IDP_URL return render(request, 'sso_post_request.html', locals()) def get_saml_request_content(key_content, cert_content, raw_xml): root = etree.fromstring(raw_xml) signed_root = signxml.XMLSigner(method=signxml.methods.enveloped, signature_algorithm=u'rsa-sha1', digest_algorithm=u'sha1', c14n_algorithm=u'http://www.w3.org/2001/10/xml-exc-c14n#').sign(root, key=key_content, passphrase='123456', cert=cert_content) return etree.tostring(signed_root)
浙公网安备 33010602011771号