Beispiel #1
0
def make_ms(desc, leaf, operator, sup=None):
    """
    Construct a signed metadata statement

    :param desc: A description of who wants who to signed what.
        represented as a dictionary containing: 'request', 'requester',
        'signer' and 'signer_add'.
    :param leaf: if the requester is the entity operator/agent
    :param operator: A dictionary containing Operator instance as values.
    :param ms: Metadata statements to be added, dict. The values are
        signed MetadataStatements.
    :param ms_uris: Metadata Statement URIs to be added. 
        Note that ms and ms_uris can not be present at the same time.
        It can be one of them or none.
    :return: A dictionary with the FO ID as key and the signed metadata 
        statement as value.
    """
    req = MetadataStatement(**desc['request'])
    _requester = operator[desc['requester']]
    req['signing_keys'] = _requester.signing_keys_as_jwks()

    _signer = operator[desc['signer']]
    if sup is None:
        sup = {}

    _fo = _signer.iss

    try:
        _ms = sup['ms']
    except KeyError:
        pass
    else:
        req['metadata_statements'] = dict(_ms.items())
        if len(_ms):
            _fo = list(_ms.keys())[0]
        else:
            _fo = ''

    try:
        _ms_uri = sup['ms_uri']
    except KeyError:
        pass
    else:
        req['metadata_statement_uris'] = dict(_ms_uri.items())
        if len(_ms_uri):
            _fo = list(_ms_uri.keys())[0]
        else:
            _fo = ''

    req.update(desc['signer_add'])

    if leaf:
        jwt_args = {'aud': [_requester.iss]}
    else:
        jwt_args = {}

    ms = _signer.pack_metadata_statement(req, jwt_args=jwt_args)

    return {_fo: ms}
Beispiel #2
0
def test_create_client_metadata_statement():
    ms = MetadataStatement(signing_keys=KEYS['org']['jwks'])
    ms_jwt = ms.to_jwt(KEYS['fo']['keyjar'].get_signing_key('rsa'))

    cms = ClientMetadataStatement(
        metadata_statements=Message(**{ISSUER['org']: ms_jwt}),
        contacts=['*****@*****.**'])

    assert cms
Beispiel #3
0
 def ace(self, req, fos, context):
     """
     Add signing keys, create metadata statement and extend request.
     
     :param req: Request 
     :param fos: List of Federation Operator IDs
     :param context: One of :py:data:`fedoidc.CONTEXTS`
     """
     _cms = MetadataStatement()
     _cms.update(req)
     _cms = self.add_signing_keys(_cms)
     sms = self.signer.create_signed_metadata_statement(_cms,
                                                        context,
                                                        fos=fos)
     self.extend_with_ms(req, sms)
Beispiel #4
0
def test_unpack_metadata_statement_uri():
    s = signer[OA['sunet']]
    req = MetadataStatement(issuer='https://example.org/op')
    # Not intermediate
    ms = s.create_signed_metadata_statement(req, 'discovery', single=True)

    jb = FSJWKSBundle('',
                      None,
                      'fo_jwks',
                      key_conv={
                          'to': quote_plus,
                          'from': unquote_plus
                      })

    mds = MetaDataStore('msd')
    op = Operator(jwks_bundle=jb)
    op.httpcli = MockHTTPClient(mds)
    res = op.unpack_metadata_statement(jwt_ms=ms)
    assert len(res.parsed_statement) == 3
    loel = op.evaluate_metadata_statement(res.result)
    assert len(loel) == 3
    assert set([l.fo for l in loel]) == {
        'https://swamid.sunet.se', 'https://edugain.com',
        'https://www.feide.no'
    }
Beispiel #5
0
    def index(self, **kwargs):
        if cherrypy.request.process_request_body is True:
            _json_doc = cherrypy.request.body.read()
        else:
            raise cherrypy.HTTPError(400, 'Missing Client registration body')

        if _json_doc == b'':
            raise cherrypy.HTTPError(400, 'Missing Client registration body')

        _args = json.loads(as_unicode(_json_doc))
        _mds = MetadataStatement(**_args)

        try:
            _mds.verify()
        except (MessageException, VerificationError) as err:
            raise cherrypy.CherryPyException(str(err))
        else:
            _jwt = self.signer.create_signed_metadata_statement(_mds,
                                                                single=True)
            cherrypy.response.headers['Content-Type'] = 'application/jwt'
            return as_bytes(_jwt)
Beispiel #6
0
def test_request_signed_by_signing_keys():
    kj = KeyJar()
    kj.issuer_keys['abc'] = KEYJAR.issuer_keys['']
    msreq = MetadataStatement(signing_keys=JWKS)
    smsreq = request_signed_by_signing_keys(kj, msreq, 'abc', 3600)

    assert smsreq

    res = verify_request_signed_by_signing_keys(smsreq)

    assert set(res.keys()) == {'ms', 'iss'}
    assert res['iss'] == 'abc'
Beispiel #7
0
def test_pack_metadata_statement_other_alg():
    _keyjar = build_keyjar(KEYDEFS)[1]
    op = Operator(keyjar=_keyjar, iss='https://example.com/')
    req = MetadataStatement(issuer='https://example.org/op')
    sms = op.pack_metadata_statement(req, alg='ES256')
    assert sms  # Should be a signed JWT
    _jwt = factory(sms)
    _body = json.loads(as_unicode(_jwt.jwt.part[1]))
    assert _body['iss'] == 'https://example.com/'
    # verify signature
    r = _jwt.verify_compact(sms, _keyjar.get_signing_key())
    assert r
Beispiel #8
0
def test_get_metadata_statement():
    jb = JWKSBundle('')
    for iss in ['https://example.org/', 'https://example.com/']:
        jb[iss] = build_keyjar(KEYDEFS)[1]

    op = Operator(keyjar=jb['https://example.com/'],
                  iss='https://example.com/')
    req = MetadataStatement(foo='bar')
    sms = op.pack_metadata_statement(req, alg='RS256')
    sms_dir = {'https://example.com': sms}
    req['metadata_statements'] = Message(**sms_dir)
    ent = FederationEntity(None, fo_bundle=jb)
    loe = ent.get_metadata_statement(req)
    assert loe
Beispiel #9
0
    def register(self, url):
        if cherrypy.request.process_request_body is True:
            _json_doc = cherrypy.request.body.read()
        else:
            raise cherrypy.HTTPError(400, 'Missing Client registration body')

        if _json_doc == b'':
            raise cherrypy.HTTPError(400, 'Missing Client registration body')

        _args = json.loads(as_unicode(_json_doc))
        _mds = MetadataStatement(**_args)

        try:
            _mds.verify()
        except (MessageException, VerificationError) as err:
            raise cherrypy.CherryPyException(str(err))
        else:
            res = requests.post(url, json=_mds.to_json())
            if 200 <= res.status_code < 300:
                self.signer.metadata_statements[url] = res.text
                cherrypy.response.headers['Content-Type'] = 'application/jwt'
                return as_bytes(res.text)
            else:
                raise cherrypy.HTTPError(message=res.text)
Beispiel #10
0
    def index(self, signer='', context='discovery', **kwargs):
        if not signer:
            raise cherrypy.HTTPError(400, 'Missing signer')
        if signer not in self.signer:
            raise cherrypy.HTTPError(400, 'unknown signer')

        if cherrypy.request.process_request_body is True:
            _json_doc = cherrypy.request.body.read()
        else:
            raise cherrypy.HTTPError(400, 'Missing Client registration body')

        if _json_doc == b'':
            raise cherrypy.HTTPError(400, 'Missing Client registration body')

        try:
            _args = json.loads(as_unicode(_json_doc))
        except json.JSONDecodeError as err:
            raise cherrypy.HTTPError(
                message="JSON decode error: {}".format(str(err)))
        _mds = MetadataStatement(**_args)

        try:
            _mds.verify()
        except (MessageException, VerificationError) as err:
            raise cherrypy.HTTPError(
                message="Message verification error: {}".format(str(err)))
        else:
            _sign = self.signer[signer]
            try:
                _resp = _sign.create_signed_metadata_statement(_mds, context)
            except (KeyError, SigningServiceError) as err:
                raise cherrypy.HTTPError(message=str(err))
            else:
                _jwt = list(_resp.values())[0]
            cherrypy.response.headers['Content-Type'] = 'application/jwt'
            return as_bytes(_jwt)
Beispiel #11
0
def test_pack_metadata_statement():
    jb = FSJWKSBundle('', None, 'fo_jwks',
                      key_conv={'to': quote_plus, 'from': unquote_plus})
    _keyjar = build_keyjar(KEYDEFS)[1]
    op = Operator(keyjar=_keyjar, jwks_bundle=jb, iss='https://example.com/')
    req = MetadataStatement(issuer='https://example.org/op')
    sms = op.pack_metadata_statement(req)
    assert sms  # Should be a signed JWT
    _jwt = factory(sms)
    assert _jwt
    assert _jwt.jwt.headers['alg'] == 'RS256'
    _body = json.loads(as_unicode(_jwt.jwt.part[1]))
    assert _body['iss'] == op.iss
    assert _body['issuer'] == 'https://example.org/op'
    # verify signature
    r = _jwt.verify_compact(sms, _keyjar.get_signing_key())
    assert r
Beispiel #12
0
def test_ace():
    jb = JWKSBundle('')
    for iss in ['https://example.org/', 'https://example.com/']:
        jb[iss] = build_keyjar(KEYDEFS)[1]
    kj = build_keyjar(KEYDEFS)[1]

    sign_serv = InternalSigningService('https://signer.example.com',
                                       signing_keys=kj)
    signer = Signer(sign_serv)
    signer.metadata_statements['response'] = {
        'https://example.org/': 'https://example.org/sms1'
    }

    ent = FederationEntity(None, keyjar=kj, signer=signer, fo_bundle=jb)
    req = MetadataStatement(foo='bar')
    ent.ace(req, ['https://example.org/'], 'response')

    assert 'metadata_statements' in req
    assert 'signing_keys' not in req
Beispiel #13
0
def verify_request_signed_by_signing_keys(smsreq):
    """
    Verify that a JWT is signed with a key that is inside the JWT.
    
    :param smsreq: Signed Metadata Statement signing request
    :return: Dictionary containing 'ms' (the signed request) and 'iss' (the
        issuer of the JWT).
    """

    _jws = factory(smsreq)
    _json = _jws.jwt.part[1]
    _body = json.loads(as_unicode(_json))
    iss = _body['iss']
    _jwks = _body['signing_keys']

    _kj = jwks_to_keyjar(_jwks, iss)

    try:
        _kid = _jws.jwt.headers['kid']
    except KeyError:
        _keys = _kj.get_signing_key(owner=iss)
    else:
        _keys = _kj.get_signing_key(owner=iss, kid=_kid)

    _ver = _jws.verify_compact(smsreq, _keys)
    # remove the JWT specific claims
    for k in JasonWebToken.c_param.keys():
        try:
            del _ver[k]
        except KeyError:
            pass
    try:
        del _ver['kid']
    except KeyError:
        pass

    return {'ms': MetadataStatement(**_ver), 'iss': iss}
Beispiel #14
0
import argparse
import json
import os

from oic.utils.keyio import KeyJar

from fedoidc import MetadataStatement
from fedoidc.signing_service import InternalSigningService

parser = argparse.ArgumentParser()
parser.add_argument('-r', dest='request')
parser.add_argument('-a', dest='alg', default='RS256')
parser.add_argument(dest="nickname")
args = parser.parse_args()

if not os.path.isdir(args.nickname):
    print('No such entity')
    exit(-1)

kj = KeyJar()
iss = open(os.path.join(args.nickname, 'iss')).read()
jwks = open(os.path.join(args.nickname, 'jwks')).read()
kj.import_jwks(jwks=json.loads(jwks), issuer=iss)

sigserv = InternalSigningService(iss=iss, signing_keys=kj, alg=args.alg)

msg = MetadataStatement()
msg.from_json(open(args.request).read())

print(sigserv(msg))
Beispiel #15
0
def test_create_metadata_statement_simple():
    ms = MetadataStatement(signing_keys=KEYS['org']['jwks'])

    assert ms
    assert len(ms['signing_keys']['keys']) == 2
Beispiel #16
0
def test_create_sms():
    s = signer[OA['sunet']]
    req = MetadataStatement(issuer='https://example.org/op')
    r = s.create_signed_metadata_statement(req, 'discovery')
    assert r
Beispiel #17
0
#!/usr/bin/env python3
import argparse
import json

from fedoidc import MetadataStatement, read_jwks_file
from fedoidc.operator import Operator

parser = argparse.ArgumentParser()
parser.add_argument('-j',
                    dest='jwks',
                    help="A JWKS containing the signers private keys")
parser.add_argument('-i', dest='iss', help='The identifier of the signer')
parser.add_argument('-r', dest='req', help='The message to sign')
parser.add_argument('-l',
                    dest='lifetime',
                    default=86400,
                    type=int,
                    help="The lifetime of the signature")
parser.add_argument('-f', dest='fo', help="The identifier of the federation")
args = parser.parse_args()

kj = read_jwks_file(args.jwks)
op = Operator(keyjar=kj, iss=args.iss, lifetime=args.lifetime)

_req = json.loads(open(args.req).read())
req = MetadataStatement(**_req)
if args.fo:
    print('{}:{}'.format(args.fo, op.pack_metadata_statement(req)))
else:
    print('{}:{}'.format(args.iss, op.pack_metadata_statement(req)))
Beispiel #18
0
from fedoidc import MetadataStatement
from fedoidc.signing_service import InternalSigningService
from fedoidc.signing_service import Signer

from oic.utils.keyio import build_keyjar

KEYDEFS= [{"type": "RSA", "key": "keys/{}.key", "use": ["sig"]}]

parser = argparse.ArgumentParser()
parser.add_argument('-i', dest='iss')
parser.add_argument('-m', dest='ms_dir', default='ms_dir')
parser.add_argument(dest="statement")
args = parser.parse_args()

_keydefs = []
for spec in KEYDEFS:
    spec['key'] = spec['key'].format(quote_plus(args.iss))
    _keydefs.append(spec)

sig_keys = build_keyjar(KEYDEFS)[1]
signing_service = InternalSigningService(iss=args.iss, signing_keys=sig_keys)
signer = Signer(signing_service, args.ms_dir)

_args = json.loads(open(args.statement,'r').read())
_mds = MetadataStatement(**_args)

_mds.verify()

print(signer.create_signed_metadata_statement(_mds, single=True))
Beispiel #19
0
_dir = os.path.join('ms_path', quote_plus(name), 'discovery')
metadata_statements = FileSystem(_dir,
                                 key_conv={
                                     'to': quote_plus,
                                     'from': unquote_plus
                                 })

fo = "https://edugain.com"

# What I want to create is something like

# (ms_OA + SK[X])
_kj = build_keyjar(config.KEY_DEFS)[1]
req = MetadataStatement(
    federation_usage='discovery',
    signing_keys={'keys': [x.serialize() for x in _kj.get_signing_key()]})

# FO(ms_OA + SK[X])
_fo_signer = operator[fo]
ms_0 = _fo_signer.pack_metadata_statement(req)

# OA(ms_IA + SK[IA] + FO(ms_OA + SK[X]))
_ia_signer = operator["https://bogus.example.org"]
req = MetadataStatement(tos_uri='https://example.org/tos',
                        metadata_statements={fo: ms_0},
                        signing_keys=_ia_signer.signing_keys_as_jwks())

oa = "https://example.org"
_oa_signer = operator[oa]
ms_1 = _oa_signer.pack_metadata_statement(req)
Beispiel #20
0
parser = argparse.ArgumentParser()
parser.add_argument('-i', dest='issuer', help="issuer id of the OP")
parser.add_argument('-c', dest='context', help="OIDC operation")
parser.add_argument('-t', dest='target')
parser.add_argument(dest="filename")
args = parser.parse_args()

oa = args.issuer
qpoa = quote_plus(oa)

_kj = KeyJar()
_jwks = json.loads(open(os.path.join('fo_jwks', qpoa)).read())
_kj.import_jwks(_jwks, oa)
sign_serv = InternalSigningService(iss=oa, signing_keys=_kj)
signer = Signer(sign_serv, ms_dir=os.path.join('ms', qpoa))

_req = open(args.filename, 'r').read()
_msg = MetadataStatement()
_msg.from_json(_req)
_res = signer.create_signed_metadata_statement(_msg, context=args.context)

for iss, sms in _res.items():
    _qp = quote_plus(iss)
    _dn = os.path.join(args.target, qpoa, args.context)
    if not os.path.isdir(_dn):
        os.makedirs(_dn)
    _fn = os.path.join(_dn, _qp)
    _fp = open(_fn, 'w')
    _fp.write(sms)
    _fp.close()