Second IDP example
This commit is contained in:
28
example/idp2/htdocs/login.mako
Normal file
28
example/idp2/htdocs/login.mako
Normal file
@@ -0,0 +1,28 @@
|
||||
<%inherit file="root.mako"/>
|
||||
|
||||
<h1>Please log in</h1>
|
||||
<p class="description">
|
||||
To register it's quite simple: enter a login and a password
|
||||
</p>
|
||||
|
||||
<form action="${action}" method="post">
|
||||
<input type="hidden" name="key" value="${key}"/>
|
||||
<input type="hidden" name="came_from" value="${came_from}"/>
|
||||
|
||||
<div class="label">
|
||||
<label for="login">Username</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" name="login" value="${login}"/><br/>
|
||||
</div>
|
||||
|
||||
<div class="label">
|
||||
<label for="password">Password</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="password" name="password"
|
||||
value="${password}"/>
|
||||
</div>
|
||||
|
||||
<input class="submit" type="submit" name="form.submitted" value="Log In"/>
|
||||
</form>
|
||||
479
example/idp2/idp.py
Executable file
479
example/idp2/idp.py
Executable file
@@ -0,0 +1,479 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import re
|
||||
import logging
|
||||
import urllib
|
||||
import time
|
||||
|
||||
from urlparse import parse_qs
|
||||
from saml2 import server, BINDING_SOAP
|
||||
from saml2 import BINDING_HTTP_REDIRECT, BINDING_HTTP_POST
|
||||
from saml2 import time_util
|
||||
from Cookie import SimpleCookie
|
||||
from saml2.httputil import Response, Redirect, Unauthorized
|
||||
from saml2.pack import http_form_post_message
|
||||
from saml2.pack import http_soap_message
|
||||
from saml2.s_utils import rndstr
|
||||
from saml2.saml import AUTHN_PASSWORD
|
||||
|
||||
logger = logging.getLogger("saml2.idp")
|
||||
|
||||
def _expiration(timeout, format="%a, %d-%b-%Y %H:%M:%S GMT"):
|
||||
if timeout == "now":
|
||||
return time_util.instant(format)
|
||||
elif timeout == "dawn":
|
||||
return time.strftime(format, time.gmtime(0))
|
||||
else:
|
||||
# validity time should match lifetime of assertions
|
||||
return time_util.in_a_while(minutes=timeout, format=format)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def dict_to_table(ava, lev=0, width=1):
|
||||
txt = ['<table border=%s bordercolor="black">\n' % width]
|
||||
for prop, valarr in ava.items():
|
||||
txt.append("<tr>\n")
|
||||
if isinstance(valarr, basestring):
|
||||
txt.append("<th>%s</th>\n" % str(prop))
|
||||
try:
|
||||
txt.append("<td>%s</td>\n" % valarr.encode("utf8"))
|
||||
except AttributeError:
|
||||
txt.append("<td>%s</td>\n" % valarr)
|
||||
elif isinstance(valarr, list):
|
||||
index = 0
|
||||
num = len(valarr)
|
||||
for val in valarr:
|
||||
if not index:
|
||||
txt.append("<th rowspan=%d>%s</td>\n" % (len(valarr), prop))
|
||||
else:
|
||||
txt.append("<tr>\n")
|
||||
if isinstance(val, dict):
|
||||
txt.append("<td>\n")
|
||||
txt.extend(dict_to_table(val, lev+1, width-1))
|
||||
txt.append("</td>\n")
|
||||
else:
|
||||
try:
|
||||
txt.append("<td>%s</td>\n" % val.encode("utf8"))
|
||||
except AttributeError:
|
||||
txt.append("<td>%s</td>\n" % val)
|
||||
if num > 1:
|
||||
txt.append("</tr>\n")
|
||||
num -= 1
|
||||
index += 1
|
||||
elif isinstance(valarr, dict):
|
||||
txt.append("<th>%s</th>\n" % prop)
|
||||
txt.append("<td>\n")
|
||||
txt.extend(dict_to_table(valarr, lev+1, width-1))
|
||||
txt.append("</td>\n")
|
||||
txt.append("</tr>\n")
|
||||
txt.append('</table>\n')
|
||||
return txt
|
||||
|
||||
def get_post(environ):
|
||||
# the environment variable CONTENT_LENGTH may be empty or missing
|
||||
try:
|
||||
request_body_size = int(environ.get('CONTENT_LENGTH', 0))
|
||||
except ValueError:
|
||||
request_body_size = 0
|
||||
|
||||
# When the method is POST the query string will be sent
|
||||
# in the HTTP request body which is passed by the WSGI server
|
||||
# in the file like wsgi.input environment variable.
|
||||
return environ['wsgi.input'].read(request_body_size)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
AUTHN = (AUTHN_PASSWORD, "http://lingon.catalogix.se/login")
|
||||
|
||||
REPOZE_ID_EQUIVALENT = "uid"
|
||||
FORM_SPEC = """<form name="myform" method="post" action="%s">
|
||||
<input type="hidden" name="SAMLResponse" value="%s" />
|
||||
<input type="hidden" name="RelayState" value="%s" />
|
||||
</form>"""
|
||||
|
||||
def _sso(environ, start_response, query, binding, user):
|
||||
if not query:
|
||||
logger.info("Missing QUERY")
|
||||
start_response('401 Unauthorized', [('Content-Type', 'text/plain')])
|
||||
return ['Unknown user']
|
||||
|
||||
# base 64 encoded request
|
||||
req_info = IDP.parse_authn_request(query["SAMLRequest"][0], binding=binding)
|
||||
resp_args = IDP.response_args(req_info.message, [BINDING_HTTP_POST],
|
||||
descr_type="spsso")
|
||||
logger.info("parsed OK")
|
||||
logger.info("%s" % req_info)
|
||||
|
||||
identity = USERS[user]
|
||||
logger.info("Identity: %s" % (identity,))
|
||||
|
||||
if REPOZE_ID_EQUIVALENT:
|
||||
identity[REPOZE_ID_EQUIVALENT] = user
|
||||
try:
|
||||
authn_resp = IDP.create_authn_response(identity, userid=user,
|
||||
authn=AUTHN, **resp_args)
|
||||
except Exception, excp:
|
||||
if logger: logger.error("Exception: %s" % (excp,))
|
||||
raise
|
||||
|
||||
if logger: logger.info("AuthNResponse: %s" % authn_resp)
|
||||
|
||||
http_args = http_form_post_message(authn_resp, resp_args["destination"],
|
||||
relay_state=query["RelayState"][0],
|
||||
typ="SAMLResponse")
|
||||
|
||||
resp = Response(http_args["data"], headers=http_args["headers"])
|
||||
return resp(environ, start_response)
|
||||
|
||||
def sso(environ, start_response, user):
|
||||
""" Supposted to return a POST """
|
||||
|
||||
logger.info("--- In SSO ---")
|
||||
logger.debug("user: %s" % user)
|
||||
logger.info("Query string: %s" % environ["QUERY_STRING"])
|
||||
extra = parse_qs(environ["QUERY_STRING"])
|
||||
logger.info("EXTRA: %s" % extra)
|
||||
logger.debug("keys: %s" % IDP.ticket.keys())
|
||||
query = parse_qs(IDP.ticket[extra["key"][0]])
|
||||
del IDP.ticket[extra["key"][0]]
|
||||
|
||||
return _sso(environ, start_response, query, BINDING_HTTP_REDIRECT, user)
|
||||
|
||||
def sso_post(environ, start_response, user):
|
||||
logger.info("--- In SSO POST ---")
|
||||
logger.debug("user: %s" % user)
|
||||
logger.info("Query string: %s" % environ["QUERY_STRING"])
|
||||
extra = parse_qs(environ["QUERY_STRING"])
|
||||
logger.info("EXTRA: %s" % extra)
|
||||
logger.debug("keys: %s" % IDP.ticket.keys())
|
||||
query = parse_qs(IDP.ticket[extra["key"][0]])
|
||||
del IDP.ticket[extra["key"][0]]
|
||||
|
||||
return _sso(environ, start_response, query, BINDING_HTTP_POST, user)
|
||||
|
||||
def whoami(environ, start_response, user):
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
identity = USERS[user].copy()
|
||||
for prop in ["login", "password"]:
|
||||
try:
|
||||
del identity[prop]
|
||||
except KeyError:
|
||||
continue
|
||||
response = dict_to_table(identity)
|
||||
return response[:]
|
||||
|
||||
def not_found(environ, start_response):
|
||||
"""Called if no URL matches."""
|
||||
start_response('404 NOT FOUND', [('Content-Type', 'text/plain')])
|
||||
return ['Not Found']
|
||||
|
||||
def not_authn(environ, start_response):
|
||||
# redirect to login page
|
||||
logger.info("not_authn ENV: %s" % environ)
|
||||
|
||||
loc = "http://%s/login" % (environ["HTTP_HOST"])
|
||||
|
||||
headers = [('Content-Type', 'text/plain')]
|
||||
if environ["REQUEST_METHOD"] == "GET":
|
||||
if "QUERY_STRING" in environ:
|
||||
query = environ["QUERY_STRING"]
|
||||
logger.info("query: %s" % query)
|
||||
key = hash(query)
|
||||
IDP.ticket[str(key)] = query
|
||||
loc += "?%s" % urllib.urlencode({"came_from": environ["PATH_INFO"],
|
||||
"key": key})
|
||||
elif environ["REQUEST_METHOD"] == "POST":
|
||||
query = get_post(environ)
|
||||
logger.info("query: %s" % query)
|
||||
key = hash(query)
|
||||
IDP.ticket[str(key)] = query
|
||||
loc += "?%s" % urllib.urlencode({"came_from": environ["PATH_INFO"],
|
||||
"key": key})
|
||||
|
||||
logger.debug("location: %s" % loc)
|
||||
logger.debug("headers: %s" % headers)
|
||||
resp = Redirect(loc, headers=headers)
|
||||
return resp(environ, start_response)
|
||||
|
||||
def do_authentication(environ, start_response, sid, cookie=None):
|
||||
"""
|
||||
Put up the login form
|
||||
"""
|
||||
query = parse_qs(environ["QUERY_STRING"])
|
||||
|
||||
logger.info("The login page")
|
||||
if cookie:
|
||||
headers = [cookie]
|
||||
else:
|
||||
headers = []
|
||||
|
||||
resp = Response(mako_template="login.mako", template_lookup=LOOKUP,
|
||||
headers=headers)
|
||||
|
||||
argv = {
|
||||
"action": "/verify",
|
||||
"came_from": query["came_from"][0],
|
||||
"login": "",
|
||||
"password": "",
|
||||
"key": query["key"][0]
|
||||
}
|
||||
logger.info("do_authentication argv: %s" % argv)
|
||||
return resp(environ, start_response, **argv)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
PASSWD = [("roland", "dianakra"),
|
||||
("babs", "howes"),
|
||||
("upper", "crust")]
|
||||
|
||||
|
||||
def verify_username_and_password(dic):
|
||||
global PASSWD
|
||||
# verify username and password
|
||||
for user, pwd in PASSWD:
|
||||
if user == dic["login"][0]:
|
||||
if pwd == dic["password"][0]:
|
||||
return True, user
|
||||
|
||||
return False, ""
|
||||
|
||||
|
||||
def do_verify(environ, start_response, _user):
|
||||
query = parse_qs(get_post(environ))
|
||||
|
||||
logger.debug("do_verify: %s" % query)
|
||||
|
||||
_ok, user = verify_username_and_password(query)
|
||||
if not _ok:
|
||||
resp = Unauthorized("Unknown user or wrong password")
|
||||
else:
|
||||
id = rndstr()
|
||||
IDP.authn[id] = user
|
||||
logger.debug("Register %s under '%s'" % (user, id))
|
||||
kaka = set_cookie("idpauthn", "/", id)
|
||||
lox = "http://%s%s?id=%s&key=%s" % (environ["HTTP_HOST"],
|
||||
query["came_from"][0], id,
|
||||
query["key"][0])
|
||||
logger.debug("Redirect => %s" % lox)
|
||||
resp = Redirect(lox, headers=[kaka], content="text/html")
|
||||
|
||||
return resp(environ, start_response)
|
||||
|
||||
def kaka2user(kaka):
|
||||
logger.debug("KAKA: %s" % kaka)
|
||||
if kaka:
|
||||
cookie_obj = SimpleCookie(kaka)
|
||||
morsel = cookie_obj.get("idpauthn", None)
|
||||
if morsel:
|
||||
return IDP.authn[morsel.value]
|
||||
else:
|
||||
logger.debug()
|
||||
return None
|
||||
|
||||
# ===========================================================================
|
||||
|
||||
def _subject_sp_info(req_info):
|
||||
# look for the subject
|
||||
subject = req_info.subject_id()
|
||||
subject = subject.text.strip()
|
||||
sp_entity_id = req_info.message.issuer.text.strip()
|
||||
return subject, sp_entity_id
|
||||
|
||||
def _slo(environ, start_response, query, user):
|
||||
try:
|
||||
req_info = IDP.parse_logout_request(query["SAMLRequest"][0],
|
||||
BINDING_HTTP_REDIRECT)
|
||||
relay_state = query["SAMLRequest"][0]
|
||||
logger.info("LOGOUT request parsed OK")
|
||||
logger.info("REQ_INFO: %s" % req_info.message)
|
||||
except KeyError, exc:
|
||||
if logger: logger.info("logout request error: %s" % (exc,))
|
||||
start_response('400 Bad request', [('Content-Type', 'text/plain')])
|
||||
return ['Request parse error']
|
||||
|
||||
subject, sp_entity_id = _subject_sp_info(req_info)
|
||||
logger.info("Logout subject: %s" % (subject,))
|
||||
logger.info("local identifier: %s" % IDP.ident.local_name(sp_entity_id,
|
||||
subject))
|
||||
# remove the authentication
|
||||
|
||||
status = None
|
||||
|
||||
# Either HTTP-Post or HTTP-redirect is possible
|
||||
bindings = [BINDING_HTTP_POST, BINDING_HTTP_REDIRECT]
|
||||
logger.debug("logout response to %s" % sp_entity_id)
|
||||
logger.debug("entity info: %s" % IDP.metadata.entity[sp_entity_id]["spsso"][0])
|
||||
(resp, headers, message) = IDP.create_logout_response(req_info.message,
|
||||
bindings)
|
||||
#headers.append(session.cookie(expire="now"))
|
||||
logger.info("Response code: %s" % (resp,))
|
||||
logger.info("Header: %s" % (headers,))
|
||||
delco = delete_cookie(environ, "idpauthn")
|
||||
if delco:
|
||||
headers.append(delco)
|
||||
start_response(resp, headers)
|
||||
return message
|
||||
|
||||
def slo(environ, start_response, user):
|
||||
""" Expects a HTTP-redirect logout request """
|
||||
|
||||
query = None
|
||||
if "QUERY_STRING" in environ:
|
||||
logger.info("Query string: %s" % environ["QUERY_STRING"])
|
||||
query = parse_qs(environ["QUERY_STRING"])
|
||||
|
||||
if not query:
|
||||
start_response('401 Unauthorized', [('Content-Type', 'text/plain')])
|
||||
return ['Unknown user']
|
||||
else:
|
||||
return _slo(environ, start_response, query, user)
|
||||
|
||||
def slo_post(environ, start_response, user):
|
||||
""" Expects a HTTP-POST logout request """
|
||||
|
||||
query = parse_qs(get_post(environ))
|
||||
return _slo(environ, start_response, query, user)
|
||||
|
||||
def slo_soap(environ, start_response, user):
|
||||
soap_message = get_post(environ)
|
||||
#logger.debug("info type: %s" % type(soap_message))
|
||||
#logger.debug("SLO_SOAP: %s" % soap_message)
|
||||
req_info = IDP.parse_logout_request("%s" % soap_message, BINDING_SOAP)
|
||||
|
||||
subject, sp_entity_id = _subject_sp_info(req_info)
|
||||
logger.info("Logout subject: %s" % (subject,))
|
||||
logger.info("local identifier: %s" % IDP.ident.local_name(sp_entity_id,
|
||||
subject))
|
||||
|
||||
response = IDP.create_logout_response(req_info.message, [BINDING_SOAP])
|
||||
args = http_soap_message(response)
|
||||
|
||||
delco = delete_cookie(environ, "idpauthn")
|
||||
if delco:
|
||||
args["headers"].append(delco)
|
||||
|
||||
resp = Response(args["data"], headers=args["headers"])
|
||||
return resp(environ, start_response)
|
||||
|
||||
|
||||
def delete_cookie(environ, name):
|
||||
kaka = environ.get("HTTP_COOKIE", '')
|
||||
if kaka:
|
||||
cookie_obj = SimpleCookie(kaka)
|
||||
morsel = cookie_obj.get(name, None)
|
||||
cookie = SimpleCookie()
|
||||
cookie[name] = ""
|
||||
cookie[name]['path'] = "/"
|
||||
logger.debug("Expire: %s" % morsel)
|
||||
cookie[name]["expires"] = _expiration("dawn")
|
||||
return tuple(cookie.output().split(": ", 1))
|
||||
return None
|
||||
|
||||
def set_cookie(name, path, value):
|
||||
cookie = SimpleCookie()
|
||||
cookie[name] = value
|
||||
cookie[name]['path'] = "/"
|
||||
cookie[name]["expires"] = _expiration(5) # 5 minutes from now
|
||||
logger.debug("Cookie expires: %s" % cookie[name]["expires"])
|
||||
return tuple(cookie.output().split(": ", 1))
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# map urls to functions
|
||||
AUTHN_URLS = [
|
||||
(r'whoami$', whoami),
|
||||
(r'whoami/(.*)$', whoami),
|
||||
(r'post_sso$', sso_post),
|
||||
(r'post_sso/(.*)$', sso_post),
|
||||
(r'sso$', sso),
|
||||
(r'sso/(.*)$', sso),
|
||||
(r'logout$', slo),
|
||||
(r'logout/(.*)$', slo),
|
||||
(r'logout_post$', slo_post),
|
||||
(r'logout_post/(.*)$', slo_post),
|
||||
(r'logout_soap$', slo_soap),
|
||||
(r'logout_soap/(.*)$', slo_soap),
|
||||
]
|
||||
|
||||
NON_AUTHN_URLS = [
|
||||
(r'login?(.*)$', do_authentication),
|
||||
(r'verify?(.*)$', do_verify),
|
||||
]
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def application(environ, start_response):
|
||||
"""
|
||||
The main WSGI application. Dispatch the current request to
|
||||
the functions from above and store the regular expression
|
||||
captures in the WSGI environment as `myapp.url_args` so that
|
||||
the functions from above can access the url placeholders.
|
||||
|
||||
If nothing matches call the `not_found` function.
|
||||
|
||||
:param environ: The HTTP application environment
|
||||
:param start_response: The application to run when the handling of the
|
||||
request is done
|
||||
:return: The response as a list of lines
|
||||
"""
|
||||
|
||||
path = environ.get('PATH_INFO', '').lstrip('/')
|
||||
kaka = environ.get("HTTP_COOKIE", None)
|
||||
logger.info("<application> PATH: %s" % path)
|
||||
|
||||
if kaka:
|
||||
logger.info("= KAKA =")
|
||||
user = kaka2user(kaka)
|
||||
else:
|
||||
try:
|
||||
query = parse_qs(environ["QUERY_STRING"])
|
||||
logger.debug("QUERY: %s" % query)
|
||||
user = IDP.authn[query["id"][0]]
|
||||
except KeyError:
|
||||
user = None
|
||||
|
||||
if not user:
|
||||
logger.info("-- No USER --")
|
||||
for regex, callback in NON_AUTHN_URLS:
|
||||
match = re.search(regex, path)
|
||||
if match is not None:
|
||||
try:
|
||||
environ['myapp.url_args'] = match.groups()[0]
|
||||
except IndexError:
|
||||
environ['myapp.url_args'] = path
|
||||
logger.info("callback: %s" % (callback,))
|
||||
return callback(environ, start_response, user)
|
||||
for regex, callback in AUTHN_URLS:
|
||||
match = re.search(regex, path)
|
||||
if match is not None:
|
||||
return not_authn(environ, start_response)
|
||||
else:
|
||||
for regex, callback in AUTHN_URLS:
|
||||
match = re.search(regex, path)
|
||||
if match is not None:
|
||||
try:
|
||||
environ['myapp.url_args'] = match.groups()[0]
|
||||
except IndexError:
|
||||
environ['myapp.url_args'] = path
|
||||
logger.info("callback: %s" % (callback,))
|
||||
return callback(environ, start_response, user)
|
||||
return not_found(environ, start_response)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
from mako.lookup import TemplateLookup
|
||||
ROOT = './'
|
||||
LOOKUP = TemplateLookup(directories=[ROOT + 'templates', ROOT + 'htdocs'],
|
||||
module_directory=ROOT + 'modules',
|
||||
input_encoding='utf-8', output_encoding='utf-8')
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from idp_user import USERS
|
||||
from wsgiref.simple_server import make_server
|
||||
|
||||
PORT = 8088
|
||||
|
||||
IDP = server.Server(sys.argv[1])
|
||||
IDP.ticket = {}
|
||||
SRV = make_server('', PORT, application)
|
||||
print "IdP listening on port: %s" % PORT
|
||||
SRV.serve_forever()
|
||||
74
example/idp2/idp_conf.py
Normal file
74
example/idp2/idp_conf.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from saml2 import BINDING_HTTP_REDIRECT
|
||||
from saml2 import BINDING_HTTP_POST
|
||||
from saml2 import BINDING_SOAP
|
||||
from saml2.saml import NAME_FORMAT_URI
|
||||
from saml2.saml import NAMEID_FORMAT_TRANSIENT
|
||||
from saml2.saml import NAMEID_FORMAT_PERSISTENT
|
||||
|
||||
#BASE = "http://lingon.ladok.umu.se:8088"
|
||||
#BASE = "http://lingon.catalogix.se:8088"
|
||||
BASE = "http://localhost:8088"
|
||||
|
||||
CONFIG={
|
||||
"entityid" : "%s/idp.xml" % BASE,
|
||||
"description": "My IDP",
|
||||
"service": {
|
||||
"idp": {
|
||||
"name" : "Rolands IdP",
|
||||
"endpoints" : {
|
||||
"single_sign_on_service":[(BASE+"/sso",BINDING_HTTP_REDIRECT),
|
||||
(BASE+"/post_sso", BINDING_HTTP_POST)],
|
||||
"single_logout_service":[(BASE+"/logout",
|
||||
BINDING_HTTP_REDIRECT),
|
||||
(BASE+"/logout_post",
|
||||
BINDING_HTTP_POST),
|
||||
(BASE+"/logout_soap",
|
||||
BINDING_SOAP)],
|
||||
},
|
||||
"policy": {
|
||||
"default": {
|
||||
"lifetime": {"minutes":15},
|
||||
"attribute_restrictions": None, # means all I have
|
||||
"name_form": NAME_FORMAT_URI
|
||||
},
|
||||
},
|
||||
"subject_data": "./idp.subject.db",
|
||||
"name_id_format": [NAMEID_FORMAT_TRANSIENT,
|
||||
NAMEID_FORMAT_PERSISTENT]
|
||||
}
|
||||
},
|
||||
"debug" : 1,
|
||||
"key_file" : "pki/mykey.pem",
|
||||
"cert_file" : "pki/mycert.pem",
|
||||
"metadata" : {
|
||||
"local": ["../sp.xml"],
|
||||
},
|
||||
"organization": {
|
||||
"display_name": "Rolands Identiteter",
|
||||
"name": "Rolands Identiteter",
|
||||
"url": "http://www.example.com",
|
||||
},
|
||||
"contact_person": [{
|
||||
"contact_type": "technical",
|
||||
"given_name": "Roland",
|
||||
"sur_name": "Hedberg",
|
||||
"email_address": "technical@example.com"
|
||||
},{
|
||||
"contact_type": "support",
|
||||
"given_name": "Support",
|
||||
"email_address": "support@example.com"
|
||||
},
|
||||
],
|
||||
# This database holds the map between a subjects local identifier and
|
||||
# the identifier returned to a SP
|
||||
#"xmlsec_binary": "/usr/local/bin/xmlsec1",
|
||||
"attribute_map_dir" : "../attributemaps",
|
||||
"logger": {
|
||||
"rotating": {
|
||||
"filename": "idp.log",
|
||||
"maxBytes": 500000,
|
||||
"backupCount": 5,
|
||||
},
|
||||
"loglevel": "debug",
|
||||
}
|
||||
}
|
||||
28
example/idp2/idp_user.py
Normal file
28
example/idp2/idp_user.py
Normal file
@@ -0,0 +1,28 @@
|
||||
USERS = {
|
||||
"roland": {
|
||||
"surname": "Hedberg",
|
||||
"givenName": "Roland",
|
||||
"eduPersonAffiliation": "staff",
|
||||
"uid": "rohe0002"
|
||||
},
|
||||
"ozzie": {
|
||||
"surname": "Guillen",
|
||||
"givenName": "Ozzie",
|
||||
"eduPersonAffiliation": "affiliate"
|
||||
},
|
||||
"derek": {
|
||||
"surname": "Jeter",
|
||||
"givenName": "Derek",
|
||||
"eduPersonAffiliation": "affiliate"
|
||||
},
|
||||
"ichiro": {
|
||||
"surname": "Suzuki",
|
||||
"givenName": "Ischiro",
|
||||
"eduPersonAffiliation": "affiliate"
|
||||
},
|
||||
"ryan": {
|
||||
"surname": "Howard",
|
||||
"givenName": "Ryan",
|
||||
"eduPersonAffiliation": "affiliate"
|
||||
}
|
||||
}
|
||||
18
example/idp2/pki/mycert.pem
Normal file
18
example/idp2/pki/mycert.pem
Normal file
@@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC8jCCAlugAwIBAgIJAJHg2V5J31I8MA0GCSqGSIb3DQEBBQUAMFoxCzAJBgNV
|
||||
BAYTAlNFMQ0wCwYDVQQHEwRVbWVhMRgwFgYDVQQKEw9VbWVhIFVuaXZlcnNpdHkx
|
||||
EDAOBgNVBAsTB0lUIFVuaXQxEDAOBgNVBAMTB1Rlc3QgU1AwHhcNMDkxMDI2MTMz
|
||||
MTE1WhcNMTAxMDI2MTMzMTE1WjBaMQswCQYDVQQGEwJTRTENMAsGA1UEBxMEVW1l
|
||||
YTEYMBYGA1UEChMPVW1lYSBVbml2ZXJzaXR5MRAwDgYDVQQLEwdJVCBVbml0MRAw
|
||||
DgYDVQQDEwdUZXN0IFNQMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkJWP7
|
||||
bwOxtH+E15VTaulNzVQ/0cSbM5G7abqeqSNSs0l0veHr6/ROgW96ZeQ57fzVy2MC
|
||||
FiQRw2fzBs0n7leEmDJyVVtBTavYlhAVXDNa3stgvh43qCfLx+clUlOvtnsoMiiR
|
||||
mo7qf0BoPKTj7c0uLKpDpEbAHQT4OF1HRYVxMwIDAQABo4G/MIG8MB0GA1UdDgQW
|
||||
BBQ7RgbMJFDGRBu9o3tDQDuSoBy7JjCBjAYDVR0jBIGEMIGBgBQ7RgbMJFDGRBu9
|
||||
o3tDQDuSoBy7JqFepFwwWjELMAkGA1UEBhMCU0UxDTALBgNVBAcTBFVtZWExGDAW
|
||||
BgNVBAoTD1VtZWEgVW5pdmVyc2l0eTEQMA4GA1UECxMHSVQgVW5pdDEQMA4GA1UE
|
||||
AxMHVGVzdCBTUIIJAJHg2V5J31I8MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF
|
||||
BQADgYEAMuRwwXRnsiyWzmRikpwinnhTmbooKm5TINPE7A7gSQ710RxioQePPhZO
|
||||
zkM27NnHTrCe2rBVg0EGz7QTd1JIwLPvgoj4VTi/fSha/tXrYUaqc9AqU1kWI4WN
|
||||
+vffBGQ09mo+6CffuFTZYeOhzP/2stAPwCTU4kxEoiy0KpZMANI=
|
||||
-----END CERTIFICATE-----
|
||||
15
example/idp2/pki/mykey.pem
Normal file
15
example/idp2/pki/mykey.pem
Normal file
@@ -0,0 +1,15 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQDkJWP7bwOxtH+E15VTaulNzVQ/0cSbM5G7abqeqSNSs0l0veHr
|
||||
6/ROgW96ZeQ57fzVy2MCFiQRw2fzBs0n7leEmDJyVVtBTavYlhAVXDNa3stgvh43
|
||||
qCfLx+clUlOvtnsoMiiRmo7qf0BoPKTj7c0uLKpDpEbAHQT4OF1HRYVxMwIDAQAB
|
||||
AoGAbx9rKH91DCw/ZEPhHsVXJ6cYHxGcMoAWvnMMC9WUN+bNo4gNL205DLfsxXA1
|
||||
jqXFXZj3+38vSFumGPA6IvXrN+Wyp3+Lz3QGc4K5OdHeBtYlxa6EsrxPgvuxYDUB
|
||||
vx3xdWPMjy06G/ML+pR9XHnRaPNubXQX3UxGBuLjwNXVmyECQQD2/D84tYoCGWoq
|
||||
5FhUBxFUy2nnOLKYC/GGxBTX62iLfMQ3fbQcdg2pJsB5rrniyZf7UL+9FOsAO9k1
|
||||
8DO7G12DAkEA7Hkdg1KEw4ZfjnnjEa+KqpyLTLRQ91uTVW6kzR+4zY719iUJ/PXE
|
||||
PxJqm1ot7mJd1LW+bWtjLpxs7jYH19V+kQJBAIEpn2JnxdmdMuFlcy/WVmDy09pg
|
||||
0z0imdexeXkFmjHAONkQOv3bWv+HzYaVMo8AgCOksfEPHGqN4eUMTfFeuUMCQF+5
|
||||
E1JSd/2yCkJhYqKJHae8oMLXByNqRXTCyiFioutK4JPYIHfugJdLfC4QziD+Xp85
|
||||
RrGCU+7NUWcIJhqfiJECQAIgUAzfzhdj5AyICaFPaOQ+N8FVMLcTyqeTXP0sIlFk
|
||||
JStVibemTRCbxdXXM7OVipz1oW3PBVEO3t/VyjiaGGg=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
37
example/idp2/templates/root.mako
Normal file
37
example/idp2/templates/root.mako
Normal file
@@ -0,0 +1,37 @@
|
||||
<% self.seen_css = set() %>
|
||||
<%def name="css_link(path, media='')" filter="trim">
|
||||
% if path not in self.seen_css:
|
||||
<link rel="stylesheet" type="text/css" href="${path|h}" media="${media}">
|
||||
% endif
|
||||
<% self.seen_css.add(path) %>
|
||||
</%def>
|
||||
<%def name="css()" filter="trim">
|
||||
${css_link('/css/main.css', 'screen')}
|
||||
</%def>
|
||||
<%def name="pre()" filter="trim">
|
||||
<div class="header">
|
||||
<h1><a href="/">Login</a></h1>
|
||||
</div>
|
||||
</%def>
|
||||
<%def name="post()" filter="trim">
|
||||
<div>
|
||||
<div class="footer">
|
||||
<p>© Copyright 2011 Umeå Universitet </p>
|
||||
</div>
|
||||
</div>
|
||||
</%def>
|
||||
##<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN "
|
||||
##"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head><title>IDP test login</title>
|
||||
${self.css()}
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
</head>
|
||||
<body>
|
||||
${pre()}
|
||||
## ${comps.dict_to_table(pageargs)}
|
||||
## <hr><hr>
|
||||
${next.body()}
|
||||
${post()}
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user