Techdebt: Remove ECDSA dependency (#7356)
This commit is contained in:
parent
3f65f94675
commit
a54cb2937f
@ -6,4 +6,4 @@ readthedocs-sphinx-search
|
|||||||
docker
|
docker
|
||||||
openapi_spec_validator
|
openapi_spec_validator
|
||||||
PyYAML>=5.1
|
PyYAML>=5.1
|
||||||
python-jose[cryptography]>=3.1.0,<4.0.0
|
joserfc>=0.9.0
|
||||||
|
@ -8,7 +8,7 @@ import typing
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from typing import Any, Dict, List, Optional, Set, Tuple
|
from typing import Any, Dict, List, Optional, Set, Tuple
|
||||||
|
|
||||||
from jose import jws
|
from joserfc import jwk, jwt
|
||||||
|
|
||||||
from moto.core.base_backend import BackendDict, BaseBackend
|
from moto.core.base_backend import BackendDict, BaseBackend
|
||||||
from moto.core.common_models import BaseModel
|
from moto.core.common_models import BaseModel
|
||||||
@ -444,7 +444,7 @@ class CognitoIdpUserPool(BaseModel):
|
|||||||
with open(
|
with open(
|
||||||
os.path.join(os.path.dirname(__file__), "resources/jwks-private.json")
|
os.path.join(os.path.dirname(__file__), "resources/jwks-private.json")
|
||||||
) as f:
|
) as f:
|
||||||
self.json_web_key = json.loads(f.read())
|
self.json_web_key = jwk.RSAKey.import_key(json.loads(f.read()))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def backend(self) -> "CognitoIdpBackend":
|
def backend(self) -> "CognitoIdpBackend":
|
||||||
@ -543,10 +543,10 @@ class CognitoIdpUserPool(BaseModel):
|
|||||||
"username" if token_use == "access" else "cognito:username": username,
|
"username" if token_use == "access" else "cognito:username": username,
|
||||||
}
|
}
|
||||||
payload.update(extra_data or {})
|
payload.update(extra_data or {})
|
||||||
headers = {"kid": "dummy"} # KID as present in jwks-public.json
|
headers = {"kid": "dummy", "alg": "RS256"} # KID as present in jwks-public.json
|
||||||
|
|
||||||
return (
|
return (
|
||||||
jws.sign(payload, self.json_web_key, headers, algorithm="RS256"),
|
jwt.encode(headers, payload, self.json_web_key),
|
||||||
expires_in,
|
expires_in,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -669,31 +669,66 @@ def generate_instance_identity_document(instance: Any) -> Dict[str, Any]:
|
|||||||
return document
|
return document
|
||||||
|
|
||||||
|
|
||||||
|
def _convert_rfc4716(data: bytes) -> bytes:
|
||||||
|
"""Convert an RFC 4716 public key to OpenSSH authorized_keys format"""
|
||||||
|
|
||||||
|
# Normalize line endings and join continuation lines
|
||||||
|
data_normalized = data.replace(b"\r\n", b"\n").replace(b"\r", b"\n")
|
||||||
|
data_joined = data_normalized.replace(b"\\\n", b"")
|
||||||
|
lines = data_joined.splitlines()
|
||||||
|
|
||||||
|
# Trim header and footer
|
||||||
|
if lines[0] != b"---- BEGIN SSH2 PUBLIC KEY ----":
|
||||||
|
raise ValueError("Invalid RFC4716 header line")
|
||||||
|
if lines[-1] != b"---- END SSH2 PUBLIC KEY ----":
|
||||||
|
raise ValueError("Invalid RFC4716 footer line")
|
||||||
|
lines = lines[1:-1]
|
||||||
|
|
||||||
|
# Leading lines containing a colon are headers
|
||||||
|
headers = {}
|
||||||
|
num_header_lines = 0
|
||||||
|
for line in lines:
|
||||||
|
if b":" not in line:
|
||||||
|
break
|
||||||
|
num_header_lines += 1
|
||||||
|
header_name, header_value = line.split(b": ")
|
||||||
|
headers[header_name.lower()] = header_value
|
||||||
|
|
||||||
|
# Remaining lines are key data
|
||||||
|
data_lines = lines[num_header_lines:]
|
||||||
|
b64_key = b"".join(data_lines)
|
||||||
|
|
||||||
|
# Extract the algo name from the binary packet
|
||||||
|
packet = base64.b64decode(b64_key)
|
||||||
|
alg_len = int.from_bytes(packet[:4], "big")
|
||||||
|
alg = packet[4 : 4 + alg_len]
|
||||||
|
|
||||||
|
result_parts = [alg, b64_key]
|
||||||
|
if b"comment" in headers:
|
||||||
|
result_parts.append(headers[b"comment"])
|
||||||
|
return b" ".join(result_parts)
|
||||||
|
|
||||||
|
|
||||||
def public_key_parse(
|
def public_key_parse(
|
||||||
key_material: Union[str, bytes]
|
key_material: Union[str, bytes]
|
||||||
) -> Union[RSAPublicKey, Ed25519PublicKey]:
|
) -> Union[RSAPublicKey, Ed25519PublicKey]:
|
||||||
# These imports take ~.5s; let's keep them local
|
|
||||||
import sshpubkeys.exceptions
|
|
||||||
from sshpubkeys.keys import SSHKey
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not isinstance(key_material, bytes):
|
if isinstance(key_material, str):
|
||||||
key_material = key_material.encode("ascii")
|
key_material = key_material.encode("ascii")
|
||||||
|
key_material = base64.b64decode(key_material)
|
||||||
|
|
||||||
decoded_key = base64.b64decode(key_material)
|
if key_material.startswith(b"---- BEGIN SSH2 PUBLIC KEY ----"):
|
||||||
public_key = SSHKey(decoded_key.decode("ascii"))
|
# cryptography doesn't parse RFC4716 key format, so we have to convert it first
|
||||||
except (sshpubkeys.exceptions.InvalidKeyException, UnicodeDecodeError):
|
key_material = _convert_rfc4716(key_material)
|
||||||
|
|
||||||
|
public_key = serialization.load_ssh_public_key(key_material)
|
||||||
|
|
||||||
|
if not isinstance(public_key, (RSAPublicKey, Ed25519PublicKey)):
|
||||||
|
raise ValueError("bad key")
|
||||||
|
except UnicodeDecodeError:
|
||||||
raise ValueError("bad key")
|
raise ValueError("bad key")
|
||||||
|
|
||||||
if public_key.rsa:
|
return public_key
|
||||||
return public_key.rsa
|
|
||||||
|
|
||||||
# `cryptography` currently does not support RSA RFC4716/SSH2 format, otherwise we could get rid of `sshpubkeys` and
|
|
||||||
# simply use `load_ssh_public_key()`
|
|
||||||
if public_key.key_type == b"ssh-ed25519":
|
|
||||||
return serialization.load_ssh_public_key(decoded_key) # type: ignore[return-value]
|
|
||||||
|
|
||||||
raise ValueError("bad key")
|
|
||||||
|
|
||||||
|
|
||||||
def public_key_fingerprint(public_key: Union[RSAPublicKey, Ed25519PublicKey]) -> str:
|
def public_key_fingerprint(public_key: Union[RSAPublicKey, Ed25519PublicKey]) -> str:
|
||||||
|
27
setup.cfg
27
setup.cfg
@ -44,13 +44,11 @@ moto = py.typed
|
|||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
all =
|
all =
|
||||||
python-jose[cryptography]>=3.1.0,<4.0.0
|
joserfc>=0.9.0
|
||||||
ecdsa!=0.15
|
|
||||||
docker>=3.0.0
|
docker>=3.0.0
|
||||||
graphql-core
|
graphql-core
|
||||||
PyYAML>=5.1
|
PyYAML>=5.1
|
||||||
cfn-lint>=0.40.0
|
cfn-lint>=0.40.0
|
||||||
sshpubkeys>=3.1.0
|
|
||||||
openapi-spec-validator>=0.5.0
|
openapi-spec-validator>=0.5.0
|
||||||
pyparsing>=3.0.7
|
pyparsing>=3.0.7
|
||||||
jsondiff>=1.1.2
|
jsondiff>=1.1.2
|
||||||
@ -59,13 +57,11 @@ all =
|
|||||||
setuptools
|
setuptools
|
||||||
multipart
|
multipart
|
||||||
proxy =
|
proxy =
|
||||||
python-jose[cryptography]>=3.1.0,<4.0.0
|
joserfc>=0.9.0
|
||||||
ecdsa!=0.15
|
|
||||||
docker>=2.5.1
|
docker>=2.5.1
|
||||||
graphql-core
|
graphql-core
|
||||||
PyYAML>=5.1
|
PyYAML>=5.1
|
||||||
cfn-lint>=0.40.0
|
cfn-lint>=0.40.0
|
||||||
sshpubkeys>=3.1.0
|
|
||||||
openapi-spec-validator>=0.5.0
|
openapi-spec-validator>=0.5.0
|
||||||
pyparsing>=3.0.7
|
pyparsing>=3.0.7
|
||||||
jsondiff>=1.1.2
|
jsondiff>=1.1.2
|
||||||
@ -74,13 +70,11 @@ proxy =
|
|||||||
setuptools
|
setuptools
|
||||||
multipart
|
multipart
|
||||||
server =
|
server =
|
||||||
python-jose[cryptography]>=3.1.0,<4.0.0
|
joserfc>=0.9.0
|
||||||
ecdsa!=0.15
|
|
||||||
docker>=3.0.0
|
docker>=3.0.0
|
||||||
graphql-core
|
graphql-core
|
||||||
PyYAML>=5.1
|
PyYAML>=5.1
|
||||||
cfn-lint>=0.40.0
|
cfn-lint>=0.40.0
|
||||||
sshpubkeys>=3.1.0
|
|
||||||
openapi-spec-validator>=0.5.0
|
openapi-spec-validator>=0.5.0
|
||||||
pyparsing>=3.0.7
|
pyparsing>=3.0.7
|
||||||
jsondiff>=1.1.2
|
jsondiff>=1.1.2
|
||||||
@ -94,8 +88,7 @@ acmpca =
|
|||||||
amp =
|
amp =
|
||||||
apigateway =
|
apigateway =
|
||||||
PyYAML>=5.1
|
PyYAML>=5.1
|
||||||
python-jose[cryptography]>=3.1.0,<4.0.0
|
joserfc>=0.9.0
|
||||||
ecdsa!=0.15
|
|
||||||
openapi-spec-validator>=0.5.0
|
openapi-spec-validator>=0.5.0
|
||||||
apigatewayv2 =
|
apigatewayv2 =
|
||||||
PyYAML>=5.1
|
PyYAML>=5.1
|
||||||
@ -112,13 +105,11 @@ batch_simple =
|
|||||||
budgets =
|
budgets =
|
||||||
ce =
|
ce =
|
||||||
cloudformation =
|
cloudformation =
|
||||||
python-jose[cryptography]>=3.1.0,<4.0.0
|
joserfc>=0.9.0
|
||||||
ecdsa!=0.15
|
|
||||||
docker>=3.0.0
|
docker>=3.0.0
|
||||||
graphql-core
|
graphql-core
|
||||||
PyYAML>=5.1
|
PyYAML>=5.1
|
||||||
cfn-lint>=0.40.0
|
cfn-lint>=0.40.0
|
||||||
sshpubkeys>=3.1.0
|
|
||||||
openapi-spec-validator>=0.5.0
|
openapi-spec-validator>=0.5.0
|
||||||
pyparsing>=3.0.7
|
pyparsing>=3.0.7
|
||||||
jsondiff>=1.1.2
|
jsondiff>=1.1.2
|
||||||
@ -133,8 +124,7 @@ codecommit =
|
|||||||
codepipeline =
|
codepipeline =
|
||||||
cognitoidentity =
|
cognitoidentity =
|
||||||
cognitoidp =
|
cognitoidp =
|
||||||
python-jose[cryptography]>=3.1.0,<4.0.0
|
joserfc>=0.9.0
|
||||||
ecdsa!=0.15
|
|
||||||
comprehend =
|
comprehend =
|
||||||
config =
|
config =
|
||||||
databrew =
|
databrew =
|
||||||
@ -150,7 +140,7 @@ dynamodbstreams =
|
|||||||
docker>=3.0.0
|
docker>=3.0.0
|
||||||
py-partiql-parser==0.5.1
|
py-partiql-parser==0.5.1
|
||||||
ebs =
|
ebs =
|
||||||
ec2 = sshpubkeys>=3.1.0
|
ec2 =
|
||||||
ec2instanceconnect =
|
ec2instanceconnect =
|
||||||
ecr =
|
ecr =
|
||||||
ecs =
|
ecs =
|
||||||
@ -204,8 +194,7 @@ redshiftdata =
|
|||||||
rekognition =
|
rekognition =
|
||||||
resourcegroups =
|
resourcegroups =
|
||||||
resourcegroupstaggingapi =
|
resourcegroupstaggingapi =
|
||||||
python-jose[cryptography]>=3.1.0,<4.0.0
|
joserfc>=0.9.0
|
||||||
ecdsa!=0.15
|
|
||||||
docker>=3.0.0
|
docker>=3.0.0
|
||||||
graphql-core
|
graphql-core
|
||||||
PyYAML>=5.1
|
PyYAML>=5.1
|
||||||
|
@ -13,13 +13,17 @@ import boto3
|
|||||||
import pytest
|
import pytest
|
||||||
import requests
|
import requests
|
||||||
from botocore.exceptions import ClientError, ParamValidationError
|
from botocore.exceptions import ClientError, ParamValidationError
|
||||||
from jose import jws, jwt
|
from joserfc import jwk, jws, jwt
|
||||||
|
|
||||||
import moto.cognitoidp.models
|
import moto.cognitoidp.models
|
||||||
from moto import mock_aws, settings
|
from moto import cognitoidp, mock_aws, settings
|
||||||
from moto.cognitoidp.utils import create_id
|
from moto.cognitoidp.utils import create_id
|
||||||
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
|
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
|
||||||
from moto.core import set_initial_no_auth_action_count
|
from moto.core import set_initial_no_auth_action_count
|
||||||
|
from moto.utilities.utils import load_resource
|
||||||
|
|
||||||
|
private_key = load_resource(cognitoidp.__name__, "resources/jwks-private.json")
|
||||||
|
PUBLIC_KEY = jwk.RSAKey.import_key(private_key)
|
||||||
|
|
||||||
|
|
||||||
@mock_aws
|
@mock_aws
|
||||||
@ -1543,7 +1547,8 @@ def test_group_in_access_token():
|
|||||||
ChallengeResponses={"USERNAME": username, "NEW_PASSWORD": new_password},
|
ChallengeResponses={"USERNAME": username, "NEW_PASSWORD": new_password},
|
||||||
)
|
)
|
||||||
|
|
||||||
claims = jwt.get_unverified_claims(result["AuthenticationResult"]["AccessToken"])
|
payload = jwt.decode(result["AuthenticationResult"]["AccessToken"], PUBLIC_KEY)
|
||||||
|
claims = payload.claims
|
||||||
assert claims["cognito:groups"] == [group_name]
|
assert claims["cognito:groups"] == [group_name]
|
||||||
|
|
||||||
|
|
||||||
@ -1604,7 +1609,8 @@ def test_other_attributes_in_id_token():
|
|||||||
ChallengeResponses={"USERNAME": username, "NEW_PASSWORD": new_password},
|
ChallengeResponses={"USERNAME": username, "NEW_PASSWORD": new_password},
|
||||||
)
|
)
|
||||||
|
|
||||||
claims = jwt.get_unverified_claims(result["AuthenticationResult"]["IdToken"])
|
payload = jwt.decode(result["AuthenticationResult"]["IdToken"], PUBLIC_KEY)
|
||||||
|
claims = payload.claims
|
||||||
assert claims["cognito:groups"] == [group_name]
|
assert claims["cognito:groups"] == [group_name]
|
||||||
assert claims["custom:myattr"] == "some val"
|
assert claims["custom:myattr"] == "some val"
|
||||||
|
|
||||||
@ -2957,7 +2963,7 @@ def test_token_legitimacy():
|
|||||||
|
|
||||||
path = "../../moto/cognitoidp/resources/jwks-public.json"
|
path = "../../moto/cognitoidp/resources/jwks-public.json"
|
||||||
with open(os.path.join(os.path.dirname(__file__), path)) as f:
|
with open(os.path.join(os.path.dirname(__file__), path)) as f:
|
||||||
json_web_key = json.loads(f.read())["keys"][0]
|
json_web_key = jwk.RSAKey.import_key(json.loads(f.read())["keys"][0])
|
||||||
|
|
||||||
for auth_flow in ["ADMIN_NO_SRP_AUTH", "ADMIN_USER_PASSWORD_AUTH"]:
|
for auth_flow in ["ADMIN_NO_SRP_AUTH", "ADMIN_USER_PASSWORD_AUTH"]:
|
||||||
outputs = authentication_flow(conn, auth_flow)
|
outputs = authentication_flow(conn, auth_flow)
|
||||||
@ -2968,14 +2974,14 @@ def test_token_legitimacy():
|
|||||||
issuer = (
|
issuer = (
|
||||||
f"https://cognito-idp.us-west-2.amazonaws.com/{outputs['user_pool_id']}"
|
f"https://cognito-idp.us-west-2.amazonaws.com/{outputs['user_pool_id']}"
|
||||||
)
|
)
|
||||||
id_claims = json.loads(jws.verify(id_token, json_web_key, "RS256"))
|
id_claims = jwt.decode(id_token, json_web_key, ["RS256"]).claims
|
||||||
assert id_claims["iss"] == issuer
|
assert id_claims["iss"] == issuer
|
||||||
assert id_claims["aud"] == client_id
|
assert id_claims["aud"] == client_id
|
||||||
assert id_claims["token_use"] == "id"
|
assert id_claims["token_use"] == "id"
|
||||||
assert id_claims["cognito:username"] == username
|
assert id_claims["cognito:username"] == username
|
||||||
for k, v in outputs["additional_fields"].items():
|
for k, v in outputs["additional_fields"].items():
|
||||||
assert id_claims[k] == v
|
assert id_claims[k] == v
|
||||||
access_claims = json.loads(jws.verify(access_token, json_web_key, "RS256"))
|
access_claims = jwt.decode(access_token, json_web_key, ["RS256"]).claims
|
||||||
assert access_claims["iss"] == issuer
|
assert access_claims["iss"] == issuer
|
||||||
assert access_claims["client_id"] == client_id
|
assert access_claims["client_id"] == client_id
|
||||||
assert access_claims["token_use"] == "access"
|
assert access_claims["token_use"] == "access"
|
||||||
@ -4938,8 +4944,10 @@ if not settings.TEST_SERVER_MODE:
|
|||||||
|
|
||||||
def verify_kid_header(token):
|
def verify_kid_header(token):
|
||||||
"""Verifies the kid-header is corresponds with the public key"""
|
"""Verifies the kid-header is corresponds with the public key"""
|
||||||
headers = jwt.get_unverified_headers(token)
|
if isinstance(token, str):
|
||||||
kid = headers["kid"]
|
token = token.encode("ascii")
|
||||||
|
sig = jws.extract_compact(token)
|
||||||
|
kid = sig.headers()["kid"]
|
||||||
|
|
||||||
key_index = -1
|
key_index = -1
|
||||||
keys = fetch_public_keys()
|
keys = fetch_public_keys()
|
||||||
|
@ -27,7 +27,7 @@ A3t8mL7r91aM5q6QOQm219lctFM8O7HRJnDgmhGpnjRwE1LyKktWTbgFZ4SNWU2X\
|
|||||||
qusUO07jKuSxzPumXBeU+JEtx0J1tqZwJlpGt2R+0qN7nKnPl2+hx \
|
qusUO07jKuSxzPumXBeU+JEtx0J1tqZwJlpGt2R+0qN7nKnPl2+hx \
|
||||||
moto@github.com"""
|
moto@github.com"""
|
||||||
|
|
||||||
RSA_PUBLIC_KEY_RFC4716 = b"""\
|
RSA_PUBLIC_KEY_RFC4716_1 = b"""\
|
||||||
---- BEGIN SSH2 PUBLIC KEY ----
|
---- BEGIN SSH2 PUBLIC KEY ----
|
||||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQDusXfgTE4eBP50NglSzCSEGnIL6+cr6m3H6cZANO
|
AAAAB3NzaC1yc2EAAAADAQABAAABAQDusXfgTE4eBP50NglSzCSEGnIL6+cr6m3H6cZANO
|
||||||
Q+P1o/W4BdtcAL3sor4iGi7SOeJgo8kweyMQrhrt6HaKGgromRiz37LQx4YIAcBi4Zd023
|
Q+P1o/W4BdtcAL3sor4iGi7SOeJgo8kweyMQrhrt6HaKGgromRiz37LQx4YIAcBi4Zd023
|
||||||
@ -38,6 +38,44 @@ wJlpGt2R+0qN7nKnPl2+hx
|
|||||||
---- END SSH2 PUBLIC KEY ----
|
---- END SSH2 PUBLIC KEY ----
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
RSA_PUBLIC_KEY_RFC4716_2 = b"""\
|
||||||
|
---- BEGIN SSH2 PUBLIC KEY ----
|
||||||
|
cOmmENt: moto@github.com
|
||||||
|
AAAAB3NzaC1yc2EAAAADAQABAAABAQDusXfgTE4eBP50NglSzCSEGnIL6+cr6m3H6cZANO
|
||||||
|
Q+P1o/W4BdtcAL3sor4iGi7SOeJgo8kweyMQrhrt6HaKGgromRiz37LQx4YIAcBi4Zd023
|
||||||
|
mO/V7Rc2Chh18mWgLSmA6ng+j37ip6452zxtv0jHAz9pJolbKBpJzbZlPN45ZCTk9ck0fS
|
||||||
|
VHRl6VRSSPQcpqi65XpRf+35zNOCGCc1mAOOTmw59Q2a6A3t8mL7r91aM5q6QOQm219lct
|
||||||
|
FM8O7HRJnDgmhGpnjRwE1LyKktWTbgFZ4SNWU2XqusUO07jKuSxzPumXBeU+JEtx0J1tqZ
|
||||||
|
wJlpGt2R+0qN7nKnPl2+hx
|
||||||
|
---- END SSH2 PUBLIC KEY ----
|
||||||
|
"""
|
||||||
|
|
||||||
|
RSA_PUBLIC_KEY_RFC4716_3 = b"""\
|
||||||
|
---- BEGIN SSH2 PUBLIC KEY ----
|
||||||
|
Comment: "1024-bit RSA, converted from OpenSSH by me@example.com"
|
||||||
|
x-command: /home/me/bin/lock-in-guest.sh
|
||||||
|
AAAAB3NzaC1yc2EAAAADAQABAAABAQDusXfgTE4eBP50NglSzCSEGnIL6+cr6m3H6cZANO
|
||||||
|
Q+P1o/W4BdtcAL3sor4iGi7SOeJgo8kweyMQrhrt6HaKGgromRiz37LQx4YIAcBi4Zd023
|
||||||
|
mO/V7Rc2Chh18mWgLSmA6ng+j37ip6452zxtv0jHAz9pJolbKBpJzbZlPN45ZCTk9ck0fS
|
||||||
|
VHRl6VRSSPQcpqi65XpRf+35zNOCGCc1mAOOTmw59Q2a6A3t8mL7r91aM5q6QOQm219lct
|
||||||
|
FM8O7HRJnDgmhGpnjRwE1LyKktWTbgFZ4SNWU2XqusUO07jKuSxzPumXBeU+JEtx0J1tqZ
|
||||||
|
wJlpGt2R+0qN7nKnPl2+hx
|
||||||
|
---- END SSH2 PUBLIC KEY ----
|
||||||
|
"""
|
||||||
|
|
||||||
|
RSA_PUBLIC_KEY_RFC4716_4 = b"""\
|
||||||
|
---- BEGIN SSH2 PUBLIC KEY ----
|
||||||
|
Comment: This is my public key for use on \
|
||||||
|
servers which I don't like.
|
||||||
|
AAAAB3NzaC1yc2EAAAADAQABAAABAQDusXfgTE4eBP50NglSzCSEGnIL6+cr6m3H6cZANO
|
||||||
|
Q+P1o/W4BdtcAL3sor4iGi7SOeJgo8kweyMQrhrt6HaKGgromRiz37LQx4YIAcBi4Zd023
|
||||||
|
mO/V7Rc2Chh18mWgLSmA6ng+j37ip6452zxtv0jHAz9pJolbKBpJzbZlPN45ZCTk9ck0fS
|
||||||
|
VHRl6VRSSPQcpqi65XpRf+35zNOCGCc1mAOOTmw59Q2a6A3t8mL7r91aM5q6QOQm219lct
|
||||||
|
FM8O7HRJnDgmhGpnjRwE1LyKktWTbgFZ4SNWU2XqusUO07jKuSxzPumXBeU+JEtx0J1tqZ
|
||||||
|
wJlpGt2R+0qN7nKnPl2+hx
|
||||||
|
---- END SSH2 PUBLIC KEY ----
|
||||||
|
"""
|
||||||
|
|
||||||
RSA_PUBLIC_KEY_FINGERPRINT = "6a:49:07:1c:7e:bd:d2:bd:96:25:fe:b5:74:83:ae:fd"
|
RSA_PUBLIC_KEY_FINGERPRINT = "6a:49:07:1c:7e:bd:d2:bd:96:25:fe:b5:74:83:ae:fd"
|
||||||
|
|
||||||
DSA_PUBLIC_KEY_OPENSSH = b"""ssh-dss \
|
DSA_PUBLIC_KEY_OPENSSH = b"""ssh-dss \
|
||||||
@ -157,10 +195,20 @@ def test_key_pairs_delete_exist_boto3():
|
|||||||
"public_key,fingerprint",
|
"public_key,fingerprint",
|
||||||
[
|
[
|
||||||
(RSA_PUBLIC_KEY_OPENSSH, RSA_PUBLIC_KEY_FINGERPRINT),
|
(RSA_PUBLIC_KEY_OPENSSH, RSA_PUBLIC_KEY_FINGERPRINT),
|
||||||
(RSA_PUBLIC_KEY_RFC4716, RSA_PUBLIC_KEY_FINGERPRINT),
|
(RSA_PUBLIC_KEY_RFC4716_1, RSA_PUBLIC_KEY_FINGERPRINT),
|
||||||
|
(RSA_PUBLIC_KEY_RFC4716_2, RSA_PUBLIC_KEY_FINGERPRINT),
|
||||||
|
(RSA_PUBLIC_KEY_RFC4716_3, RSA_PUBLIC_KEY_FINGERPRINT),
|
||||||
|
(RSA_PUBLIC_KEY_RFC4716_4, RSA_PUBLIC_KEY_FINGERPRINT),
|
||||||
(ED25519_PUBLIC_KEY_OPENSSH, ED25519_PUBLIC_KEY_FINGERPRINT),
|
(ED25519_PUBLIC_KEY_OPENSSH, ED25519_PUBLIC_KEY_FINGERPRINT),
|
||||||
],
|
],
|
||||||
ids=["rsa-openssh", "rsa-rfc4716", "ed25519"],
|
ids=[
|
||||||
|
"rsa-openssh",
|
||||||
|
"rsa-rfc4716-1",
|
||||||
|
"rsa-rfc4716-2",
|
||||||
|
"rsa-rfc4716-3",
|
||||||
|
"rsa-rfc4716-4",
|
||||||
|
"ed25519",
|
||||||
|
],
|
||||||
)
|
)
|
||||||
def test_key_pairs_import_boto3(public_key, fingerprint):
|
def test_key_pairs_import_boto3(public_key, fingerprint):
|
||||||
client = boto3.client("ec2", "us-west-1")
|
client = boto3.client("ec2", "us-west-1")
|
||||||
@ -188,6 +236,18 @@ def test_key_pairs_import_boto3(public_key, fingerprint):
|
|||||||
assert kp1["KeyName"] in all_names
|
assert kp1["KeyName"] in all_names
|
||||||
|
|
||||||
|
|
||||||
|
@mock_aws
|
||||||
|
def test_key_pairs_import_invalid_key():
|
||||||
|
client = boto3.client("ec2", "us-west-1")
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
client.import_key_pair(
|
||||||
|
KeyName="sth", PublicKeyMaterial="---- BEGIN SSH2 PUBLIC KEY ----\nsth"
|
||||||
|
)
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
assert err["Code"] == "InvalidKeyPair.Format"
|
||||||
|
|
||||||
|
|
||||||
@mock_aws
|
@mock_aws
|
||||||
def test_key_pairs_import_exist_boto3():
|
def test_key_pairs_import_exist_boto3():
|
||||||
client = boto3.client("ec2", "us-west-1")
|
client = boto3.client("ec2", "us-west-1")
|
||||||
|
Loading…
Reference in New Issue
Block a user