Esempio n. 1
0
 def test_malformed_assertions(self):
     errors = (ValueError, TrustError)
     # This one doesn't actually contain an assertion
     assertion = encode_json_bytes({})
     self.assertRaises(errors, self.verifier.verify, assertion)
     # This one has no certificates
     pub, priv = get_keypair("TEST")
     assertion = bundle_certs_and_assertion([], jwt.generate({"aud": "TEST"}, priv))
     self.assertRaises(errors, self.verifier.verify, assertion)
     # This one has too many certificates in the chain.
     assertion = bundle_certs_and_assertion(
         [jwt.generate({}, priv), jwt.generate({}, priv)], jwt.generate({"aud": "TEST"}, priv)
     )
     self.assertRaises(errors, self.verifier.verify, assertion)
def build_assertion(keypair, certificate, audience, exp=None, new_style=True):
	"""
	Generate a new assertion for the given email address.

	This method lets you generate BrowserID assertions. Called with just
	an email and audience it will generate an assertion from
	login.persona.org.
	"""
	logging.debug("build_assertion()")

	#Default expiry to 5 minutes
	if exp is None:
		exp = int((time.time() + (5*60)) * 1000)

	pubkey, privkey = keypair

	#TODO - verify keypair matches certificate

	# Generate the assertion, signed with email's public key.
	assertion = {
		"exp": exp,
		"aud": audience,
	}
	assertion = jwt.generate(assertion, privkey.get_key())

	#print "assertion:\n" + assertion

	# Combine them into a BrowserID bundled assertion.
	return bundle_certs_and_assertion([certificate], assertion, new_style)
Esempio n. 3
0
 def test_malformed_assertions(self):
     errors = (ValueError, TrustError)
     # This one doesn't actually contain an assertion
     assertion = encode_json_bytes({})
     self.assertRaises(errors, self.verifier.verify, assertion)
     # This one has no certificates
     pub, priv = get_keypair("TEST")
     assertion = bundle_certs_and_assertion(
         [],
         jwt.generate({"aud": "TEST"}, priv),
     )
     self.assertRaises(errors, self.verifier.verify, assertion)
     # This one has too many certificates in the chain.
     assertion = bundle_certs_and_assertion(
         [jwt.generate({}, priv), jwt.generate({}, priv)],
         jwt.generate({"aud": "TEST"}, priv),
     )
     self.assertRaises(errors, self.verifier.verify, assertion)
Esempio n. 4
0
def make_assertion(email,
                   audience,
                   issuer=None,
                   exp=None,
                   assertion_sig=None,
                   certificate_sig=None,
                   new_style=True,
                   email_keypair=None,
                   issuer_keypair=None):
    """Generate a new dummy assertion for the given email address.

    This method lets you generate BrowserID assertions using dummy private
    keys. Called with just an email and audience it will generate an assertion
    from login.persona.org.

    By specifying the "exp", "assertion_sig" or "certificate_sig" arguments
    it is possible generate invalid assertions for testing purposes.
    """
    if issuer is None:
        issuer = "login.persona.org"
    if exp is None:
        exp = int((time.time() + 60) * 1000)
    # Get private key for the email address itself.
    if email_keypair is None:
        email_keypair = get_keypair(email)
    email_pub, email_priv = email_keypair
    # Get private key for the hostname so we can sign it.
    if issuer_keypair is None:
        issuer_keypair = get_keypair(issuer)
    iss_pub, iss_priv = issuer_keypair

    # Generate the assertion, signed with email's public key.
    assertion = {
        "exp": exp,
        "aud": audience,
    }
    assertion = jwt.generate(assertion, email_priv)
    if assertion_sig is not None:
        assertion = ".".join(
            assertion.split(".")[:-1] + [encode_bytes(assertion_sig)])
    # Generate the certificate signing the email's public key
    # with the issuer's public key.
    certificate = {
        "iss": issuer,
        "exp": exp,
        "principal": {
            "email": email
        },
        "public-key": email_pub,
    }
    certificate = jwt.generate(certificate, iss_priv)
    if certificate_sig is not None:
        certificate = ".".join(
            certificate.split(".")[:-1] + [encode_bytes(certificate_sig)])
    # Combine them into a BrowserID bundled assertion.
    return bundle_certs_and_assertion([certificate], assertion, new_style)
Esempio n. 5
0
def make_assertion(email, audience, issuer=None, exp=None,
                    assertion_sig=None, certificate_sig=None,
                    new_style=True, email_keypair=None, issuer_keypair=None,
                    idp_claims=None, user_claims=None):
    """Generate a new dummy assertion for the given email address.

    This method lets you generate BrowserID assertions using dummy private
    keys. Called with just an email and audience it will generate an assertion
    from login.persona.org.

    By specifying the "exp", "assertion_sig" or "certificate_sig" arguments
    it is possible generate invalid assertions for testing purposes.
    """
    if issuer is None:
        issuer = "login.persona.org"
    if exp is None:
        exp = int((time.time() + 60) * 1000)
    # Get private key for the email address itself.
    if email_keypair is None:
        email_keypair = get_keypair(email)
    email_pub, email_priv = email_keypair
    # Get private key for the hostname so we can sign it.
    if issuer_keypair is None:
        issuer_keypair = get_keypair(issuer)
    iss_pub, iss_priv = issuer_keypair

    # Generate the assertion, signed with email's public key.
    assertion = {
        "exp": exp,
        "aud": audience,
    }
    if user_claims:
        assertion.update(user_claims)
    assertion = jwt.generate(assertion, email_priv)
    if assertion_sig is not None:
        assertion = ".".join(assertion.split(".")[:-1] +
                                [encode_bytes(assertion_sig)])
    # Generate the certificate signing the email's public key
    # with the issuer's public key.
    certificate = {
        "iss": issuer,
        "exp": exp,
        "principal": {"email": email},
        "public-key": email_pub,
    }
    if idp_claims:
        certificate.update(idp_claims)
    certificate = jwt.generate(certificate, iss_priv)
    if certificate_sig is not None:
        certificate = ".".join(certificate.split(".")[:-1] +
                                [encode_bytes(certificate_sig)])
    # Combine them into a BrowserID bundled assertion.
    return bundle_certs_and_assertion([certificate], assertion, new_style)
Esempio n. 6
0
def main():
    arguments = docopt(HELP)
    host = arguments["--host"].rstrip('/')
    headers = {'content-type': 'application/json'}

    if arguments["--version"]:
        print("msisdn-cli %s" % __version__)
        sys.exit(0)

    verify = True
    if arguments["--insecure"]:
        verify = False

    # 1. Start the discover
    url = "%s/discover" % host
    discover_args = {"mcc": arguments["--mcc"], "roaming": False}
    if arguments["--mnc"] is not None:
        discover_args["mnc"] = arguments["--mnc"]
    if arguments["--msisdn"] is not None:
        discover_args["msisdn"] = arguments["--msisdn"]

    r = requests.post(url,
                      json.dumps(discover_args),
                      headers=headers,
                      verify=verify)
    try:
        r.raise_for_status()
    except:
        print(url, r.content)
        raise

    discover = r.json()

    # 1.1 Register
    url = "%s/register" % host
    r = requests.post(url, headers=headers, verify=verify)
    try:
        r.raise_for_status()
    except:
        print(url, r.content)
        raise

    register = r.json()
    hawk_auth = HawkAuth(hawk_session=register["msisdnSessionToken"],
                         server_url=host)
    hawkId = hawk_auth.credentials["id"]

    method = discover['verificationMethods'][0]

    try:
        mtSender = discover['verificationDetails'][method]["mtSender"]
    except KeyError:
        mtSender = ''

    # 2. If MT Flow
    if method == "sms/mt":
        # 2.1 If no MSISDN, ask the MSISDN
        if arguments["--msisdn"] is None:
            msisdn = input("Please enter your MSISDN number (ie +123456789): ")
        else:
            msisdn = arguments["--msisdn"]

        # 2.2 Start the registration
        print("MT Flow for %s" % msisdn)
        url = "%s/sms/mt/verify" % host
        verify_args = {
            "msisdn": msisdn,
            "mcc": discover_args["mcc"],
            "shortVerificationCode": True
        }
        r = requests.post(url,
                          json.dumps(verify_args),
                          auth=hawk_auth,
                          headers=headers,
                          verify=verify)
        try:
            r.raise_for_status()
        except:
            print(url, r.content)
            raise

    # 3. If MOMT Flow
    else:
        print("MOMT Flow")
        # 3.1 Give the Number and HawkId
        moVerifier = discover['verificationDetails']["sms/momt"]["moVerifier"]
        print("Please send the following message to %s:" % moVerifier)
        print("\n\tSMS %s\n" % hawkId.decode("ascii"))

    # 4. Ask for the code
    code = input("Please enter the code that you will get by SMS from %s: " %
                 mtSender)

    # 5. Verify the code
    url = "%s/sms/verify_code" % host
    r = requests.post(url,
                      json.dumps({"code": code.strip()}),
                      auth=hawk_auth,
                      headers=headers,
                      verify=verify)
    try:
        r.raise_for_status()
    except:
        print(url, r.content)
        raise

    # 6. Print out the certificate
    publicKey, privateKey = get_keypair("msisdn")
    url = "%s/certificate/sign" % host
    sign_args = {
        "publicKey": json.dumps(publicKey),
        "duration": 86400  # One day
    }
    r = requests.post(url,
                      json.dumps(sign_args),
                      auth=hawk_auth,
                      headers=headers,
                      verify=verify)
    try:
        r.raise_for_status()
    except:
        print(url, r.content)
        raise

    sign = r.json()
    cert = sign["cert"]
    info = json.loads(decode_bytes(cert.split('.')[1]).decode("utf-8"))
    info["publicKey"] = "<stripped>"
    info["public-key"] = "<stripped>"
    info["pubkey"] = "<stripped>"
    print("Verified: %s" % json.dumps(info, indent=2, sort_keys=True))

    # Build assertion
    if arguments["--audience"]:
        audience = arguments["--audience"]

        assertion = {"exp": int((time.time() + 60) * 1000), "aud": audience}

        assertion = bundle_certs_and_assertion([cert],
                                               jwt.generate(
                                                   assertion, privateKey))

        if arguments["--verbose"]:
            print("BID Assertion for %s:\n\n%s\n\n" % (audience, assertion))

        if arguments["--dry-run"]:
            curl = """\ncurl -X POST -D - \\
        -H 'Authorization: BROWSERID %s' \\""" % assertion

            if arguments["--data"]:
                curl += """
             -d '%s' \\""" % arguments["--data"]
            if arguments["--json"]:
                curl += """
        -H 'Content-Type: application/json' -H 'Accept: application/json' \\
        -d '%s' \\""" % arguments["--json"]

            login_endpoint = arguments["--login-endpoint"] or "<login_URL>"
            curl += "\n        %s\n" "" % login_endpoint

            print("\nTo validate the configuration of the service provider, "
                  "you can run the curl command below.\n\n"
                  "You should get a 200 OK status code with a "
                  "Hawk-Session-Token header:\n\n")

            print(curl)
            print(ERROR_EXPLAINATION)
        else:
            headers = {"Authorization": "BROWSERID %s" % assertion}
            data = arguments["--data"]
            if arguments["--json"]:
                data = arguments["--json"]
                headers["Content-Type"] = "application/json"
                headers["Accept"] = "application/json"
            r = requests.post(arguments["--login-endpoint"],
                              data=data,
                              headers=headers,
                              verify=verify)

            # Try to extract an Hawk sessionToken from the response.
            sessionToken = None
            if "Access-Control-Expose-Headers" in r.headers:
                tokenHeader = r.headers["Access-Control-Expose-Headers"]
                sessionHeaders = tokenHeader.split(",")
                sessionHeader = None
                for header in sessionHeaders:
                    if "token" in header.lower():
                        sessionHeader = header.strip()
                        break
                if sessionHeader:
                    sessionToken = r.headers[sessionHeader]
            else:
                try:
                    json_resp = r.json()
                    for key in json_resp.keys():
                        if "token" in key.lower():
                            sessionToken = json_resp["key"]
                except ValueError:
                    pass

            print("Status: %s" % r.status_code)
            if sessionToken:
                print("Hawk sessionToken: %s" % sessionToken)
            else:
                print("Headers: %s" % r.headers)
                print("Content: %s" % r.content)
Esempio n. 7
0
def main():
    arguments = docopt(HELP)
    host = arguments["--host"].rstrip('/')
    headers = {'content-type': 'application/json'}

    if arguments["--version"]:
        print("msisdn-cli %s" % __version__)
        sys.exit(0)

    verify = True
    if arguments["--insecure"]:
        verify = False

    # 1. Start the discover
    url = "%s/discover" % host
    discover_args = {"mcc": arguments["--mcc"], "roaming": False}
    if arguments["--mnc"] is not None:
        discover_args["mnc"] = arguments["--mnc"]
    if arguments["--msisdn"] is not None:
        discover_args["msisdn"] = arguments["--msisdn"]

    r = requests.post(url, json.dumps(discover_args),
                      headers=headers, verify=verify)
    try:
        r.raise_for_status()
    except:
        print(url, r.content)
        raise

    discover = r.json()

    # 1.1 Register
    url = "%s/register" % host
    r = requests.post(url, headers=headers, verify=verify)
    try:
        r.raise_for_status()
    except:
        print(url, r.content)
        raise

    register = r.json()
    hawk_auth = HawkAuth(hawk_session=register["msisdnSessionToken"],
                         server_url=host)
    hawkId = hawk_auth.credentials["id"]

    method = discover['verificationMethods'][0]

    try:
        mtSender = discover['verificationDetails'][method]["mtSender"]
    except KeyError:
        mtSender = ''

    # 2. If MT Flow
    if method == "sms/mt":
        # 2.1 If no MSISDN, ask the MSISDN
        if arguments["--msisdn"] is None:
            msisdn = input("Please enter your MSISDN number (ie +123456789): ")
        else:
            msisdn = arguments["--msisdn"]

        # 2.2 Start the registration
        print("MT Flow for %s" % msisdn)
        url = "%s/sms/mt/verify" % host
        verify_args = {
            "msisdn": msisdn,
            "mcc": discover_args["mcc"],
            "shortVerificationCode": True
        }
        r = requests.post(url, json.dumps(verify_args),
                          auth=hawk_auth, headers=headers, verify=verify)
        try:
            r.raise_for_status()
        except:
            print(url, r.content)
            raise

    # 3. If MOMT Flow
    else:
        print("MOMT Flow")
        # 3.1 Give the Number and HawkId
        moVerifier = discover['verificationDetails']["sms/momt"]["moVerifier"]
        print("Please send the following message to %s:" % moVerifier)
        print("\n\tSMS %s\n" % hawkId.decode("ascii"))

    # 4. Ask for the code
    code = input(
        "Please enter the code that you will get by SMS from %s: " % mtSender
    )

    # 5. Verify the code
    url = "%s/sms/verify_code" % host
    r = requests.post(url, json.dumps({"code": code.strip()}),
                      auth=hawk_auth, headers=headers, verify=verify)
    try:
        r.raise_for_status()
    except:
        print(url, r.content)
        raise

    # 6. Print out the certificate
    publicKey, privateKey = get_keypair("msisdn")
    url = "%s/certificate/sign" % host
    sign_args = {
        "publicKey": json.dumps(publicKey),
        "duration": 86400  # One day
    }
    r = requests.post(url, json.dumps(sign_args),
                      auth=hawk_auth, headers=headers, verify=verify)
    try:
        r.raise_for_status()
    except:
        print(url, r.content)
        raise

    sign = r.json()
    cert = sign["cert"]
    info = json.loads(decode_bytes(cert.split('.')[1]).decode("utf-8"))
    info["publicKey"] = "<stripped>"
    info["public-key"] = "<stripped>"
    info["pubkey"] = "<stripped>"
    print("Verified: %s" % json.dumps(info, indent=2, sort_keys=True))

    # Build assertion
    if arguments["--audience"]:
        audience = arguments["--audience"]

        assertion = {
            "exp": int((time.time() + 60) * 1000),
            "aud": audience
        }

        assertion = bundle_certs_and_assertion(
            [cert], jwt.generate(assertion, privateKey)
        )

        if arguments["--verbose"]:
            print("BID Assertion for %s:\n\n%s\n\n" % (audience, assertion))

        if arguments["--dry-run"]:
            curl = """\ncurl -X POST -D - \\
        -H 'Authorization: BROWSERID %s' \\""" % assertion

            if arguments["--data"]:
                curl += """
             -d '%s' \\""" % arguments["--data"]
            if arguments["--json"]:
                curl += """
        -H 'Content-Type: application/json' -H 'Accept: application/json' \\
        -d '%s' \\""" % arguments["--json"]

            login_endpoint = arguments["--login-endpoint"] or "<login_URL>"
            curl += "\n        %s\n""" % login_endpoint

            print("\nTo validate the configuration of the service provider, "
                  "you can run the curl command below.\n\n"
                  "You should get a 200 OK status code with a "
                  "Hawk-Session-Token header:\n\n")

            print(curl)
            print(ERROR_EXPLAINATION)
        else:
            headers = {"Authorization": "BROWSERID %s" % assertion}
            data = arguments["--data"]
            if arguments["--json"]:
                data = arguments["--json"]
                headers["Content-Type"] = "application/json"
                headers["Accept"] = "application/json"
            r = requests.post(arguments["--login-endpoint"], data=data,
                              headers=headers, verify=verify)

            # Try to extract an Hawk sessionToken from the response.
            sessionToken = None
            if "Access-Control-Expose-Headers" in r.headers:
                tokenHeader = r.headers["Access-Control-Expose-Headers"]
                sessionHeaders = tokenHeader.split(",")
                sessionHeader = None
                for header in sessionHeaders:
                    if "token" in header.lower():
                        sessionHeader = header.strip()
                        break
                if sessionHeader:
                    sessionToken = r.headers[sessionHeader]
            else:
                try:
                    json_resp = r.json()
                    for key in json_resp.keys():
                        if "token" in key.lower():
                            sessionToken = json_resp["key"]
                except ValueError:
                    pass

            print("Status: %s" % r.status_code)
            if sessionToken:
                print("Hawk sessionToken: %s" % sessionToken)
            else:
                print("Headers: %s" % r.headers)
                print("Content: %s" % r.content)