package aws_signing_helper import ( "bytes" "crypto" "crypto/ecdsa" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/sha512" "errors" "fmt" "io/ioutil" "log" "math/big" "net/http" "net/http/httptest" "os" "os/exec" "strings" "testing" "time" "unicode/utf8" "github.com/aws/aws-sdk-go/aws/request" ) const TestCredentialsFilePath = "/tmp/credentials" func setup() error { generateCredentialProcessDataScript := exec.Command("/bin/bash", "../generate-credential-process-data.sh") _, err := generateCredentialProcessDataScript.Output() return err } func TestMain(m *testing.M) { err := setup() if err != nil { log.Println(err.Error()) os.Exit(1) } code := m.Run() os.Exit(code) } // Simple struct to define fixtures type CertData struct { CertPath string KeyType string } // Certificate fixtures should be generated by the script ./generate-certs.sh // if they do not exist, or need to be updated. func TestReadCertificateData(t *testing.T) { fixtures := []CertData{ {"../tst/certs/ec-prime256v1-sha256-cert.pem", "EC"}, {"../tst/certs/rsa-2048-sha256-cert.pem", "RSA"}, } for _, fixture := range fixtures { certData, _, err := ReadCertificateData(fixture.CertPath) if err != nil { t.Log("Failed to read certificate data") t.Fail() } if certData.KeyType != fixture.KeyType { t.Logf("Wrong key type. Expected %s, got %s", fixture.KeyType, certData.KeyType) t.Fail() } } } func TestReadInvalidCertificateData(t *testing.T) { _, _, err := ReadCertificateData("../tst/certs/invalid-rsa-cert.pem") if err == nil || !strings.Contains(err.Error(), "could not parse certificate") { t.Log("Failed to throw a handled error") t.Fail() } } func TestReadCertificateBundleData(t *testing.T) { fixtures := []string{ "../tst/certs/cert-bundle.pem", "../tst/certs/cert-bundle-with-comments.pem", } for _, fixture := range fixtures { _, err := ReadCertificateBundleData(fixture) if err != nil { t.Log("Failed to read certificate bundle data") t.Fail() } } } func TestReadPrivateKeyData(t *testing.T) { fixtures := []string{ "../tst/certs/ec-prime256v1-key.pem", "../tst/certs/ec-prime256v1-key-pkcs8.pem", "../tst/certs/rsa-2048-key.pem", "../tst/certs/rsa-2048-key-pkcs8.pem", } for _, fixture := range fixtures { _, err := ReadPrivateKeyData(fixture) if err != nil { t.Log(fixture) t.Log(err) t.Log("Failed to read private key data") t.Fail() } } } func TestReadInvalidPrivateKeyData(t *testing.T) { _, err := ReadPrivateKeyData("../tst/certs/invalid-rsa-key.pem") if err == nil || !strings.Contains(err.Error(), "unable to parse private key") { t.Log("Failed to throw a handled error") t.Fail() } } func TestBuildAuthorizationHeader(t *testing.T) { testRequest, err := http.NewRequest("POST", "https://rolesanywhere.us-west-2.amazonaws.com", nil) if err != nil { t.Log(err) t.Fail() } path := "../tst/certs/rsa-2048-sha256-cert.pem" certificateList1, _ := ReadCertificateBundleData(path) certificate1 := certificateList1[0] pkPath := "../tst/certs/rsa-2048-key.pem" awsRequest := request.Request{HTTPRequest: testRequest} signer, signingAlgorithm, err := GetFileSystemSigner(pkPath, "", path, false) if err != nil { t.Log(err) t.Fail() } certificate, err := signer.Certificate() if err != nil { t.Log(err) t.Fail() } if !bytes.Equal(certificate.Raw, certificate1.Raw) { t.Log("Certificate does not match signer certificate") t.Fail() } certificateChain, err := signer.CertificateChain() if err != nil { t.Log(err) t.Fail() } for i, cert := range certificateChain { if !bytes.Equal(cert.Raw, certificateList1[i].Raw) { t.Log("Certificate chain does not match signer certificate chain") t.Fail() } } requestSignFunction := CreateRequestSignFunction(signer, signingAlgorithm, certificate, certificateChain) requestSignFunction(&awsRequest) certificateList2, _ := ReadCertificateBundleData("../tst/certs/rsa-2048-2-sha256-cert.pem") certificate2 := certificateList2[0] os.Rename("../tst/certs/rsa-2048-sha256-cert.pem", "../tst/certs/rsa-2048-sha256-cert.pem.bak") os.Rename("../tst/certs/rsa-2048-2-sha256-cert.pem", "../tst/certs/rsa-2048-sha256-cert.pem") certificate, err = signer.Certificate() if err != nil { t.Log(err) t.Fail() } if !bytes.Equal(certificate.Raw, certificate2.Raw) { t.Log("Certificate does not match signer certificate after update") t.Fail() } certificateChain, err = signer.CertificateChain() if err != nil { t.Log(err) t.Fail() } for i, cert := range certificateChain { if !bytes.Equal(cert.Raw, certificateList2[i].Raw) { t.Log("Certificate chain does not match signer certificate chain after update") t.Fail() } } os.Rename("../tst/certs/rsa-2048-sha256-cert.pem", "../tst/certs/rsa-2048-2-sha256-cert.pem") os.Rename("../tst/certs/rsa-2048-sha256-cert.pem.bak", "../tst/certs/rsa-2048-sha256-cert.pem") requestSignFunction2 := CreateRequestSignFunction(signer, signingAlgorithm, certificate, certificateChain) requestSignFunction2(&awsRequest) } // Verify that the provided payload was signed correctly with the provided options. // This function is specifically used for unit testing. func Verify(payload []byte, publicKey crypto.PublicKey, digest crypto.Hash, sig []byte) (bool, error) { var hash []byte switch digest { case crypto.SHA256: sum := sha256.Sum256(payload) hash = sum[:] case crypto.SHA384: sum := sha512.Sum384(payload) hash = sum[:] case crypto.SHA512: sum := sha512.Sum512(payload) hash = sum[:] default: log.Fatal("unsupported digest") return false, errors.New("unsupported digest") } { publicKey, ok := publicKey.(*ecdsa.PublicKey) if ok { valid := ecdsa.VerifyASN1(publicKey, hash, sig) return valid, nil } } { publicKey, ok := publicKey.(*rsa.PublicKey) if ok { err := rsa.VerifyPKCS1v15(publicKey, digest, hash, sig) return err == nil, nil } } return false, nil } func TestSign(t *testing.T) { msg := "test message" testTable := []CredentialsOpts{} // TODO: Include tests for PKCS#12 containers, once fixtures are created // with end-entity certificates. ec_digests := []string{"sha1", "sha256", "sha384", "sha512"} ec_curves := []string{"prime256v1", "secp384r1"} for _, digest := range ec_digests { for _, curve := range ec_curves { cert := fmt.Sprintf("../tst/certs/ec-%s-%s-cert.pem", curve, digest) key := fmt.Sprintf("../tst/certs/ec-%s-key.pem", curve) testTable = append(testTable, CredentialsOpts{ CertificateId: cert, PrivateKeyId: key, }) key = fmt.Sprintf("../tst/certs/ec-%s-key-pkcs8.pem", curve) testTable = append(testTable, CredentialsOpts{ CertificateId: cert, PrivateKeyId: key, }) } } rsa_digests := []string{"md5", "sha1", "sha256", "sha384", "sha512"} rsa_key_lengths := []string{"1024", "2048", "4096"} for _, digest := range rsa_digests { for _, keylen := range rsa_key_lengths { cert := fmt.Sprintf("../tst/certs/rsa-%s-%s-cert.pem", keylen, digest) key := fmt.Sprintf("../tst/certs/rsa-%s-key.pem", keylen) testTable = append(testTable, CredentialsOpts{ CertificateId: cert, PrivateKeyId: key, }) key = fmt.Sprintf("../tst/certs/rsa-%s-key-pkcs8.pem", keylen) testTable = append(testTable, CredentialsOpts{ CertificateId: cert, PrivateKeyId: key, }) } } pkcs11_objects := []string{"rsa-2048", "ec-prime256v1"} for _, object := range pkcs11_objects { base_pkcs11_uri := "pkcs11:token=credential-helper-test?pin-value=1234" basic_pkcs11_uri := fmt.Sprintf("pkcs11:token=credential-helper-test;object=%s?pin-value=1234", object) always_auth_pkcs11_uri := fmt.Sprintf("pkcs11:token=credential-helper-test;object=%s-always-auth?pin-value=1234", object) cert_file := fmt.Sprintf("../tst/certs/%s-sha256-cert.pem", object) testTable = append(testTable, CredentialsOpts{ CertificateId: basic_pkcs11_uri, }) testTable = append(testTable, CredentialsOpts{ PrivateKeyId: basic_pkcs11_uri, }) testTable = append(testTable, CredentialsOpts{ CertificateId: basic_pkcs11_uri, PrivateKeyId: basic_pkcs11_uri, }) testTable = append(testTable, CredentialsOpts{ CertificateId: cert_file, PrivateKeyId: basic_pkcs11_uri, }) testTable = append(testTable, CredentialsOpts{ CertificateId: basic_pkcs11_uri, PrivateKeyId: always_auth_pkcs11_uri, ReusePin: true, }) testTable = append(testTable, CredentialsOpts{ CertificateId: cert_file, PrivateKeyId: always_auth_pkcs11_uri, ReusePin: true, }) // Note that for the below test case, there are two matching keys. // Both keys will validate with the certificate, and one will be chosen // (it doesn't matter which, since both are the exact same key - it's // just that one has the CKA_ALWAYS_AUTHENTICATE attribute set). testTable = append(testTable, CredentialsOpts{ CertificateId: cert_file, PrivateKeyId: base_pkcs11_uri, ReusePin: true, }) } digestList := []crypto.Hash{crypto.SHA256, crypto.SHA384, crypto.SHA512} for _, credOpts := range testTable { signer, _, err := GetSigner(&credOpts) if err != nil { var logMsg string if credOpts.CertificateId != "" || credOpts.PrivateKeyId != "" { logMsg = fmt.Sprintf("Failed to get signer for '%s'/'%s'", credOpts.CertificateId, credOpts.PrivateKeyId) } else { logMsg = fmt.Sprintf("Failed to get signer for '%s'", credOpts.CertIdentifier.Subject) } t.Log(logMsg) t.Fail() return } pubKey := signer.Public() if credOpts.CertificateId != "" && pubKey == nil { t.Log(fmt.Sprintf("Signer didn't provide public key for '%s'/'%s'", credOpts.CertificateId, credOpts.PrivateKeyId)) t.Fail() return } for _, digest := range digestList { signatureBytes, err := signer.Sign(rand.Reader, []byte(msg), digest) // Try signing again to make sure that there aren't any issues // with reopening sessions. Also, in some test cases, signing again // makes sure that the context-specific PIN was saved. signer.Sign(rand.Reader, []byte(msg), digest) if err != nil { t.Log("Failed to sign the input message") t.Fail() return } _, err = signer.Sign(rand.Reader, []byte(msg), digest) if err != nil { t.Log("Failed second signature on the input message") t.Fail() return } if pubKey != nil { valid, _ := Verify([]byte(msg), pubKey, digest, signatureBytes) if !valid { t.Log(fmt.Sprintf("Failed to verify the signature for '%s'/'%s'", credOpts.CertificateId, credOpts.PrivateKeyId)) t.Fail() return } } } signer.Close() } } func TestCredentialProcess(t *testing.T) { testTable := []struct { name string server *httptest.Server }{ { name: "create-session-server-response", server: GetMockedCreateSessionResponseServer(), }, } for _, tc := range testTable { credentialsOpts := CredentialsOpts{ PrivateKeyId: "../credential-process-data/client-key.pem", CertificateId: "../credential-process-data/client-cert.pem", RoleArn: "arn:aws:iam::000000000000:role/ExampleS3WriteRole", ProfileArnStr: "arn:aws:rolesanywhere:us-east-1:000000000000:profile/41cl0bae-6783-40d4-ab20-65dc5d922e45", TrustAnchorArnStr: "arn:aws:rolesanywhere:us-east-1:000000000000:trust-anchor/41cl0bae-6783-40d4-ab20-65dc5d922e45", Endpoint: tc.server.URL, SessionDuration: 900, } t.Run(tc.name, func(t *testing.T) { defer tc.server.Close() signer, signatureAlgorithm, err := GetSigner(&credentialsOpts) if err != nil { t.Log("Failed to get signer") t.Fail() return } resp, err := GenerateCredentials(&credentialsOpts, signer, signatureAlgorithm) if err != nil { t.Log(err) t.Log("Unable to call credential-process") t.Fail() } if resp.AccessKeyId != "accessKeyId" { t.Log("Incorrect access key id") t.Fail() } if resp.SecretAccessKey != "secretAccessKey" { t.Log("Incorrect secret access key") t.Fail() } if resp.SessionToken != "sessionToken" { t.Log("Incorrect session token") t.Fail() } }) } } func TestCertStoreSignerCreationFails(t *testing.T) { testTable := []CredentialsOpts{} randomLargeSerial := new(big.Int) randomLargeSerial.SetString("123456719012345678901234567890", 10) testTable = append(testTable, CredentialsOpts{ CertIdentifier: CertIdentifier{ Subject: "invalid-subject", }, }) testTable = append(testTable, CredentialsOpts{ CertIdentifier: CertIdentifier{ Issuer: "invalid-issuer", }, }) testTable = append(testTable, CredentialsOpts{ CertIdentifier: CertIdentifier{ SerialNumber: randomLargeSerial, }, }) testTable = append(testTable, CredentialsOpts{ CertIdentifier: CertIdentifier{ Subject: "CN=roles-anywhere-rsa-2048-sha25", SerialNumber: randomLargeSerial, }, }) for _, credOpts := range testTable { _, _, err := GetSigner(&credOpts) if err == nil { t.Log("Expected failure when creating certificate store signer, but received none") t.Fail() } } } func TestSignerCreationFails(t *testing.T) { var cert string testTable := []CredentialsOpts{} ec_digests := []string{"sha1", "sha256", "sha384", "sha512"} ec_curves := []string{"prime256v1", "secp384r1"} for _, digest := range ec_digests { for _, curve := range ec_curves { cert = fmt.Sprintf("../tst/certs/ec-%s-%s.p12", curve, digest) testTable = append(testTable, CredentialsOpts{ CertificateId: cert, }) } } rsa_digests := []string{"md5", "sha1", "sha256", "sha384", "sha512"} rsa_key_lengths := []string{"1024", "2048", "4096"} for _, digest := range rsa_digests { for _, keylen := range rsa_key_lengths { cert = fmt.Sprintf("../tst/certs/rsa-%s-%s.p12", keylen, digest) testTable = append(testTable, CredentialsOpts{ CertificateId: cert, }) } } for _, credOpts := range testTable { _, _, err := GetSigner(&credOpts) // We expect a failure since the certificates in these .p12 files are // self-signed. When creating a signer, we expect there to be an // end-entity certificate within the container. if err == nil { t.Log("Expected failure when creating PKCS#12 signer, but received none") t.Fail() } } } func TestPKCS11SignerCreationFails(t *testing.T) { testTable := []CredentialsOpts{} template_uri := "pkcs11:token=credential-helper-test;object=%s?pin-value=1234" rsa_generic_uri := fmt.Sprintf(template_uri, "rsa-2048") ec_generic_uri := fmt.Sprintf(template_uri, "ec-prime256v1") always_auth_rsa_uri := fmt.Sprintf(template_uri, "rsa-2048-always-auth") always_auth_ec_uri := fmt.Sprintf(template_uri, "ec-prime256v1-always-auth") testTable = append(testTable, CredentialsOpts{ CertificateId: rsa_generic_uri, PrivateKeyId: ec_generic_uri, }) testTable = append(testTable, CredentialsOpts{ CertificateId: ec_generic_uri, PrivateKeyId: rsa_generic_uri, }) testTable = append(testTable, CredentialsOpts{ CertificateId: "../tst/certs/ec-prime256v1-sha256-cert.pem", PrivateKeyId: rsa_generic_uri, }) testTable = append(testTable, CredentialsOpts{ CertificateId: "../tst/certs/rsa-2048-sha256-cert.pem", PrivateKeyId: ec_generic_uri, }) testTable = append(testTable, CredentialsOpts{ CertificateId: rsa_generic_uri, PrivateKeyId: always_auth_ec_uri, ReusePin: true, }) testTable = append(testTable, CredentialsOpts{ CertificateId: ec_generic_uri, PrivateKeyId: always_auth_rsa_uri, ReusePin: true, }) testTable = append(testTable, CredentialsOpts{ CertificateId: "../tst/certs/ec-prime256v1-sha256-cert.pem", PrivateKeyId: always_auth_rsa_uri, ReusePin: true, }) testTable = append(testTable, CredentialsOpts{ CertificateId: "../tst/certs/rsa-2048-sha256-cert.pem", PrivateKeyId: always_auth_ec_uri, ReusePin: true, }) for _, credOpts := range testTable { _, _, err := GetSigner(&credOpts) if err == nil { t.Log("Expected failure when creating PKCS#11 signer, but received none") t.Fail() } } } func TestUpdate(t *testing.T) { testTable := []struct { name string server *httptest.Server inputFileContents string profile string expectedFileContents string }{ { name: "test-space-separated-keys", server: GetMockedCreateSessionResponseServer(), inputFileContents: `test test test [test profile] aws_access_key_id = test [test] aws_secret_access_key = test`, profile: "test profile", expectedFileContents: `test test test [test profile] aws_access_key_id = accessKeyId aws_secret_access_key = secretAccessKey aws_session_token = sessionToken [test] aws_secret_access_key = test`, }, { name: "test-profile-with-other-keys", server: GetMockedCreateSessionResponseServer(), inputFileContents: `test test test [test profile] aws_access_key_id = test test_key = test [test] aws_secret_access_key = test`, profile: "test profile", expectedFileContents: `test test test [test profile] aws_access_key_id = accessKeyId test_key = test aws_secret_access_key = secretAccessKey aws_session_token = sessionToken [test] aws_secret_access_key = test`, }, { name: "test-commented-profile", server: GetMockedCreateSessionResponseServer(), inputFileContents: `test test test # [test profile] aws_access_key_id = test [test] aws_secret_access_key = test`, profile: "test profile", expectedFileContents: `test test test # [test profile] aws_access_key_id = test [test] aws_secret_access_key = test [test profile] aws_access_key_id = accessKeyId aws_secret_access_key = secretAccessKey aws_session_token = sessionToken `, }, { name: "test-profile-does-not-exist", server: GetMockedCreateSessionResponseServer(), inputFileContents: `test test test [test] aws_secret_access_key = test`, profile: "test profile", expectedFileContents: `test test test [test] aws_secret_access_key = test [test profile] aws_access_key_id = accessKeyId aws_secret_access_key = secretAccessKey aws_session_token = sessionToken `, }, { name: "test-first-word-in-profile-matches", server: GetMockedCreateSessionResponseServer(), inputFileContents: `test test test [test profile] aws_access_key_id = test [test] aws_secret_access_key = test`, profile: "test", expectedFileContents: `test test test [test profile] aws_access_key_id = test [test] aws_access_key_id = accessKeyId aws_secret_access_key = secretAccessKey aws_session_token = sessionToken`, }, { name: "test-multiple-profiles-with-same-name", server: GetMockedCreateSessionResponseServer(), inputFileContents: `test test test [test] test_key = test [test profile] aws_access_key_id = test [test] aws_secret_access_key = test`, profile: "test", expectedFileContents: `test test test [test] test_key = test aws_access_key_id = accessKeyId aws_secret_access_key = secretAccessKey aws_session_token = sessionToken [test profile] aws_access_key_id = test [test] aws_secret_access_key = test`, }, } for _, tc := range testTable { credentialsOpts := CredentialsOpts{ PrivateKeyId: "../credential-process-data/client-key.pem", CertificateId: "../credential-process-data/client-cert.pem", RoleArn: "arn:aws:iam::000000000000:role/ExampleS3WriteRole", ProfileArnStr: "arn:aws:rolesanywhere:us-east-1:000000000000:profile/41cl0bae-6783-40d4-ab20-65dc5d922e45", TrustAnchorArnStr: "arn:aws:rolesanywhere:us-east-1:000000000000:trust-anchor/41cl0bae-6783-40d4-ab20-65dc5d922e45", Endpoint: tc.server.URL, SessionDuration: 900, } t.Run(tc.name, func(t *testing.T) { SetupTests() defer tc.server.Close() os.Setenv(AwsSharedCredentialsFileEnvVarName, TestCredentialsFilePath) _, err := GetCredentialsFileContents() // first create the credentials file with the appropriate permissions if err != nil { t.Log("unable to create credentials file for testing") t.Fail() } writeOnlyCredentialsFile, err := GetWriteOnlyCredentialsFile() // then obtain a handle to the credentials file to perform write operations if err != nil { t.Log("unable to write to credentials file for testing") t.Fail() } defer writeOnlyCredentialsFile.Close() writeOnlyCredentialsFile.WriteString(tc.inputFileContents) Update(credentialsOpts, tc.profile, true) fileByteContents, _ := ioutil.ReadFile(TestCredentialsFilePath) fileStringContents := trimLastChar(string(fileByteContents)) if fileStringContents != tc.expectedFileContents { t.Log("unexpected file contents") t.Fail() } }) } } func TestUpdateFilePermissions(t *testing.T) { testTable := []struct { name string server *httptest.Server profile string expectedFileContents string }{ { name: "test-space-separated-keys", server: GetMockedCreateSessionResponseServer(), profile: "test profile", expectedFileContents: `[test profile] aws_access_key_id = accessKeyId aws_secret_access_key = secretAccessKey aws_session_token = sessionToken `, }, } for _, tc := range testTable { credentialsOpts := CredentialsOpts{ PrivateKeyId: "../credential-process-data/client-key.pem", CertificateId: "../credential-process-data/client-cert.pem", RoleArn: "arn:aws:iam::000000000000:role/ExampleS3WriteRole", ProfileArnStr: "arn:aws:rolesanywhere:us-east-1:000000000000:profile/41cl0bae-6783-40d4-ab20-65dc5d922e45", TrustAnchorArnStr: "arn:aws:rolesanywhere:us-east-1:000000000000:trust-anchor/41cl0bae-6783-40d4-ab20-65dc5d922e45", Endpoint: tc.server.URL, SessionDuration: 900, } t.Run(tc.name, func(t *testing.T) { SetupTests() defer tc.server.Close() os.Setenv(AwsSharedCredentialsFileEnvVarName, TestCredentialsFilePath) Update(credentialsOpts, tc.profile, true) fileByteContents, _ := ioutil.ReadFile(TestCredentialsFilePath) fileStringContents := trimLastChar(string(fileByteContents)) if fileStringContents != tc.expectedFileContents { t.Log("unexpected file contents") t.Fail() } info, _ := os.Stat(TestCredentialsFilePath) mode := info.Mode() if mode != ((1 << 8) | (1 << 7)) { t.Log("unexpected file mode") t.Fail() } }) } } func TestGenerateLongToken(t *testing.T) { _, err := GenerateToken(150) if err == nil { t.Log("token generation should've failed since token size is too large") t.Fail() } } func TestGenerateToken(t *testing.T) { token1, err := GenerateToken(100) if err != nil { t.Log("unexpected failure in generating token") t.Fail() } token2, err := GenerateToken(100) if err != nil { t.Log("unexpected failure in generating token") t.Fail() } if token1 == token2 { t.Log("expected two randomly generated tokens to be different") t.Fail() } } func TestStoreValidToken(t *testing.T) { token, err := GenerateToken(100) if err != nil { t.Log("unexpected failure in generating token") t.Fail() } err = InsertToken(token, time.Now().Add(time.Second*time.Duration(100))) if err != nil { t.Log("unexpected failure when inserting token") t.Fail() } httpRequest, err := http.NewRequest("GET", "http://127.0.0.1", nil) if err != nil { t.Log("unable to create test http request") t.Fail() } httpRequest.Header.Add(Ec2MetadataTokenHeader, token) err = CheckValidToken(nil, httpRequest) if err != nil { t.Log("expected previously inserted token to be valid") t.Fail() } } func Test(t *testing.T) { httpRequest, err := http.NewRequest("GET", "http://127.0.0.1", nil) if err != nil { t.Log("unable to create test http request") t.Fail() } httpRequest.Header.Add("test-header", "test-header-value") headerNames := [4]string{"Test-Header", "test-header", "TEST-HEADER", "tEST-hEadeR"} for _, header := range headerNames { testHeaderValue := httpRequest.Header.Get(header) if testHeaderValue != "test-header-value" { t.Log("header name canonicalization not working as expected") t.Fail() } } } func SetupTests() { os.Remove(TestCredentialsFilePath) } func trimLastChar(s string) string { r, size := utf8.DecodeLastRuneInString(s) if r == utf8.RuneError && (size == 0 || size == 1) { size = 0 } return s[:len(s)-size] } func GetMockedCreateSessionResponseServer() *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) w.Write([]byte(`{ "credentialSet":[ { "assumedRoleUser": { "arn": "arn:aws:sts::000000000000:assumed-role/ExampleS3WriteRole", "assumedRoleId": "assumedRoleId" }, "credentials":{ "accessKeyId": "accessKeyId", "expiration": "2022-07-27T04:36:55Z", "secretAccessKey": "secretAccessKey", "sessionToken": "sessionToken" }, "packedPolicySize": 10, "roleArn": "arn:aws:iam::000000000000:role/ExampleS3WriteRole", "sourceIdentity": "sourceIdentity" } ], "subjectArn": "arn:aws:rolesanywhere:us-east-1:000000000000:subject/41cl0bae-6783-40d4-ab20-65dc5d922e45" }`)) })) }