625 619 |
|
626 620 | make_test!(assume_role_override_global_env_url);
|
627 621 | make_test!(assume_role_override_service_env_url);
|
628 622 | make_test!(assume_role_override_global_profile_url);
|
629 623 | make_test!(assume_role_override_service_profile_url);
|
630 624 | }
|
631 625 |
|
632 626 | #[cfg(all(test, feature = "sso"))]
|
633 627 | mod sso_tests {
|
634 628 | use crate::{profile::credentials::Builder, provider_config::ProviderConfig};
|
635 - | use aws_credential_types::credential_feature::AwsCredentialFeature;
|
636 629 | use aws_credential_types::provider::ProvideCredentials;
|
637 630 | use aws_sdk_sso::config::RuntimeComponents;
|
638 631 | use aws_smithy_runtime_api::client::{
|
639 632 | http::{
|
640 633 | HttpClient, HttpConnector, HttpConnectorFuture, HttpConnectorSettings,
|
641 634 | SharedHttpConnector,
|
642 635 | },
|
643 636 | orchestrator::{HttpRequest, HttpResponse},
|
644 637 | };
|
645 638 | use aws_smithy_types::body::SdkBody;
|
646 639 | use aws_types::os_shim_internal::{Env, Fs};
|
647 640 | use std::collections::HashMap;
|
648 641 |
|
649 - | #[derive(Debug)]
|
650 - | struct ClientInner {
|
651 - | expected_token: &'static str,
|
652 - | }
|
653 - | impl HttpConnector for ClientInner {
|
654 - | fn call(&self, request: HttpRequest) -> HttpConnectorFuture {
|
655 - | assert_eq!(
|
656 - | self.expected_token,
|
657 - | request.headers().get("x-amz-sso_bearer_token").unwrap()
|
658 - | );
|
659 - | HttpConnectorFuture::ready(Ok(HttpResponse::new(
|
642 + | // TODO(https://github.com/awslabs/aws-sdk-rust/issues/1117) This test is ignored on Windows because it uses Unix-style paths
|
643 + | #[cfg_attr(windows, ignore)]
|
644 + | // In order to preserve the SSO token cache, the inner provider must only
|
645 + | // be created once, rather than once per credential resolution.
|
646 + | #[tokio::test]
|
647 + | async fn create_inner_provider_exactly_once() {
|
648 + | #[derive(Debug)]
|
649 + | struct ClientInner {
|
650 + | expected_token: &'static str,
|
651 + | }
|
652 + | impl HttpConnector for ClientInner {
|
653 + | fn call(&self, request: HttpRequest) -> HttpConnectorFuture {
|
654 + | assert_eq!(
|
655 + | self.expected_token,
|
656 + | request.headers().get("x-amz-sso_bearer_token").unwrap()
|
657 + | );
|
658 + | HttpConnectorFuture::ready(Ok(HttpResponse::new(
|
660 659 | 200.try_into().unwrap(),
|
661 660 | SdkBody::from("{\"roleCredentials\":{\"accessKeyId\":\"ASIARTESTID\",\"secretAccessKey\":\"TESTSECRETKEY\",\"sessionToken\":\"TESTSESSIONTOKEN\",\"expiration\": 1651516560000}}"),
|
662 661 | )))
|
662 + | }
|
663 663 | }
|
664 - | }
|
665 - | #[derive(Debug)]
|
666 - | struct Client {
|
667 - | inner: SharedHttpConnector,
|
668 - | }
|
669 - | impl Client {
|
670 - | fn new(expected_token: &'static str) -> Self {
|
671 - | Self {
|
672 - | inner: SharedHttpConnector::new(ClientInner { expected_token }),
|
664 + | #[derive(Debug)]
|
665 + | struct Client {
|
666 + | inner: SharedHttpConnector,
|
667 + | }
|
668 + | impl Client {
|
669 + | fn new(expected_token: &'static str) -> Self {
|
670 + | Self {
|
671 + | inner: SharedHttpConnector::new(ClientInner { expected_token }),
|
672 + | }
|
673 673 | }
|
674 674 | }
|
675 - | }
|
676 - | impl HttpClient for Client {
|
677 - | fn http_connector(
|
678 - | &self,
|
679 - | _settings: &HttpConnectorSettings,
|
680 - | _components: &RuntimeComponents,
|
681 - | ) -> SharedHttpConnector {
|
682 - | self.inner.clone()
|
675 + | impl HttpClient for Client {
|
676 + | fn http_connector(
|
677 + | &self,
|
678 + | _settings: &HttpConnectorSettings,
|
679 + | _components: &RuntimeComponents,
|
680 + | ) -> SharedHttpConnector {
|
681 + | self.inner.clone()
|
682 + | }
|
683 683 | }
|
684 - | }
|
685 684 |
|
686 - | fn create_test_fs() -> Fs {
|
687 - | Fs::from_map({
|
685 + | let fs = Fs::from_map({
|
688 686 | let mut map = HashMap::new();
|
689 687 | map.insert(
|
690 688 | "/home/.aws/config".to_string(),
|
691 689 | br#"
|
692 690 | [profile default]
|
693 691 | sso_session = dev
|
694 692 | sso_account_id = 012345678901
|
695 693 | sso_role_name = SampleRole
|
696 694 | region = us-east-1
|
697 695 |
|
698 696 | [sso-session dev]
|
699 697 | sso_region = us-east-1
|
700 698 | sso_start_url = https://d-abc123.awsapps.com/start
|
701 699 | "#
|
702 700 | .to_vec(),
|
703 701 | );
|
704 702 | map.insert(
|
705 703 | "/home/.aws/sso/cache/34c6fceca75e456f25e7e99531e2425c6c1de443.json".to_string(),
|
706 704 | br#"
|
707 705 | {
|
708 706 | "accessToken": "secret-access-token",
|
709 707 | "expiresAt": "2199-11-14T04:05:45Z",
|
710 708 | "refreshToken": "secret-refresh-token",
|
711 709 | "clientId": "ABCDEFG323242423121312312312312312",
|
712 710 | "clientSecret": "ABCDE123",
|
713 711 | "registrationExpiresAt": "2199-03-06T19:53:17Z",
|
714 712 | "region": "us-east-1",
|
715 713 | "startUrl": "https://d-abc123.awsapps.com/start"
|
716 714 | }
|
717 715 | "#
|
718 716 | .to_vec(),
|
719 717 | );
|
720 718 | map
|
721 - | })
|
722 - | }
|
723 - |
|
724 - | // TODO(https://github.com/awslabs/aws-sdk-rust/issues/1117) This test is ignored on Windows because it uses Unix-style paths
|
725 - | #[cfg_attr(windows, ignore)]
|
726 - | // In order to preserve the SSO token cache, the inner provider must only
|
727 - | // be created once, rather than once per credential resolution.
|
728 - | #[tokio::test]
|
729 - | async fn create_inner_provider_exactly_once() {
|
730 - | let fs = create_test_fs();
|
731 - |
|
719 + | });
|
732 720 | let provider_config = ProviderConfig::empty()
|
733 721 | .with_fs(fs.clone())
|
734 722 | .with_env(Env::from_slice(&[("HOME", "/home")]))
|
735 723 | .with_http_client(Client::new("secret-access-token"));
|
736 724 | let provider = Builder::default().configure(&provider_config).build();
|
737 725 |
|
738 726 | let first_creds = provider.provide_credentials().await.unwrap();
|
739 727 |
|
740 728 | // Write to the token cache with an access token that won't match the fake client's
|
741 729 | // expected access token, and thus, won't return SSO credentials.
|
742 730 | fs.write(
|
743 731 | "/home/.aws/sso/cache/34c6fceca75e456f25e7e99531e2425c6c1de443.json",
|
744 732 | r#"
|
745 733 | {
|
746 734 | "accessToken": "NEW!!secret-access-token",
|
747 735 | "expiresAt": "2199-11-14T04:05:45Z",
|
748 736 | "refreshToken": "secret-refresh-token",
|
749 737 | "clientId": "ABCDEFG323242423121312312312312312",
|
750 738 | "clientSecret": "ABCDE123",
|
751 739 | "registrationExpiresAt": "2199-03-06T19:53:17Z",
|
752 740 | "region": "us-east-1",
|
753 741 | "startUrl": "https://d-abc123.awsapps.com/start"
|
754 742 | }
|
755 743 | "#,
|
756 744 | )
|
757 745 | .await
|
758 746 | .unwrap();
|
759 747 |
|
760 748 | // Loading credentials will still work since the SSOTokenProvider should have only
|
761 749 | // been created once, and thus, the correct token is still in an in-memory cache.
|
762 750 | let second_creds = provider
|
763 751 | .provide_credentials()
|
764 752 | .await
|
765 753 | .expect("used cached token instead of loading from the file system");
|
766 754 | assert_eq!(first_creds, second_creds);
|
767 755 |
|
768 756 | // Now create a new provider, which should use the new cached token value from the file system
|
769 757 | // since it won't have the in-memory cache. We do this just to verify that the FS mutation above
|
770 758 | // actually worked correctly.
|
771 759 | let provider_config = ProviderConfig::empty()
|
772 760 | .with_fs(fs.clone())
|
773 761 | .with_env(Env::from_slice(&[("HOME", "/home")]))
|
774 762 | .with_http_client(Client::new("NEW!!secret-access-token"));
|
775 763 | let provider = Builder::default().configure(&provider_config).build();
|
776 764 | let third_creds = provider.provide_credentials().await.unwrap();
|
777 765 | assert_eq!(second_creds, third_creds);
|
778 766 | }
|
779 - |
|
780 - | #[cfg_attr(windows, ignore)]
|
781 - | #[tokio::test]
|
782 - | async fn credential_feature() {
|
783 - | let fs = create_test_fs();
|
784 - |
|
785 - | let provider_config = ProviderConfig::empty()
|
786 - | .with_fs(fs.clone())
|
787 - | .with_env(Env::from_slice(&[("HOME", "/home")]))
|
788 - | .with_http_client(Client::new("secret-access-token"));
|
789 - | let provider = Builder::default().configure(&provider_config).build();
|
790 - |
|
791 - | let creds = provider.provide_credentials().await.unwrap();
|
792 - |
|
793 - | assert_eq!(
|
794 - | &vec![
|
795 - | AwsCredentialFeature::CredentialsSso,
|
796 - | AwsCredentialFeature::CredentialsProfile
|
797 - | ],
|
798 - | creds.get_property::<Vec<AwsCredentialFeature>>().unwrap()
|
799 - | )
|
800 - | }
|
801 767 | }
|