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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user