graph_oauth/identity/credentials/
client_credentials_authorization_url.rs1use reqwest::IntoUrl;
2
3use url::Url;
4use uuid::Uuid;
5
6use graph_error::{AuthorizationFailure, IdentityResult};
7
8use crate::identity::{credentials::app_config::AppConfig, Authority, AzureCloudInstance};
9use crate::oauth_serializer::{AuthParameter, AuthSerializer};
10use crate::{ClientAssertionCredentialBuilder, ClientSecretCredentialBuilder};
11
12#[cfg(feature = "openssl")]
13use crate::identity::{ClientCertificateCredentialBuilder, X509Certificate};
14
15#[derive(Default, Debug, Clone, Serialize, Deserialize)]
16pub struct ClientCredentialAdminConsentResponse {
17 pub admin_consent: bool,
18 pub tenant: String,
19}
20
21#[derive(Clone)]
22pub struct ClientCredentialsAuthorizationUrlParameters {
23 pub(crate) app_config: AppConfig,
25 pub(crate) state: Option<String>,
26}
27
28impl ClientCredentialsAuthorizationUrlParameters {
29 pub fn new(
30 client_id: impl AsRef<str>,
31 redirect_uri: impl IntoUrl,
32 ) -> IdentityResult<ClientCredentialsAuthorizationUrlParameters> {
33 let redirect_uri_result = Url::parse(redirect_uri.as_str());
34 let redirect_uri = redirect_uri.into_url().or(redirect_uri_result)?;
35
36 Ok(ClientCredentialsAuthorizationUrlParameters {
37 app_config: AppConfig::builder(client_id.as_ref())
38 .redirect_uri(redirect_uri)
39 .build(),
40 state: None,
41 })
42 }
43
44 pub fn builder<T: AsRef<str>>(
45 client_id: T,
46 ) -> ClientCredentialsAuthorizationUrlParameterBuilder {
47 ClientCredentialsAuthorizationUrlParameterBuilder::new(client_id)
48 }
49
50 pub fn with_client_secret(
51 self,
52 client_secret: impl AsRef<str>,
53 ) -> ClientSecretCredentialBuilder {
54 ClientSecretCredentialBuilder::new_with_client_secret(client_secret, self.app_config)
55 }
56
57 pub fn with_client_assertion(
58 self,
59 signed_assertion: impl AsRef<str>,
60 ) -> ClientAssertionCredentialBuilder {
61 ClientAssertionCredentialBuilder::new_with_signed_assertion(
62 signed_assertion,
63 self.app_config,
64 )
65 }
66
67 #[cfg(feature = "openssl")]
68 pub fn with_client_x509_certificate(
69 self,
70 _client_secret: impl AsRef<str>,
71 x509: &X509Certificate,
72 ) -> IdentityResult<ClientCertificateCredentialBuilder> {
73 ClientCertificateCredentialBuilder::new_with_certificate(x509, self.app_config)
74 }
75
76 pub fn url(&self) -> IdentityResult<Url> {
77 self.url_with_host(&self.app_config.azure_cloud_instance)
78 }
79
80 pub fn url_with_host(&self, azure_cloud_instance: &AzureCloudInstance) -> IdentityResult<Url> {
81 let mut serializer = AuthSerializer::new();
82 let client_id = self.app_config.client_id.to_string();
83 if client_id.trim().is_empty() || self.app_config.client_id.is_nil() {
84 return AuthorizationFailure::result(AuthParameter::ClientId.alias());
85 }
86
87 if self.app_config.redirect_uri.is_none() {
88 return AuthorizationFailure::result(AuthParameter::RedirectUri.alias());
89 }
90
91 if let Some(redirect_uri) = self.app_config.redirect_uri.as_ref() {
92 serializer.redirect_uri(redirect_uri.as_str());
93 }
94
95 serializer.client_id(client_id.as_str());
96
97 if let Some(state) = self.state.as_ref() {
98 serializer.state(state.as_ref());
99 }
100
101 let mut uri = azure_cloud_instance.admin_consent_uri(&self.app_config.authority)?;
102 let query = serializer.encode_query(
103 vec![AuthParameter::State],
104 vec![AuthParameter::ClientId, AuthParameter::RedirectUri],
105 )?;
106 uri.set_query(Some(query.as_str()));
107 Ok(uri)
108 }
109}
110
111#[derive(Clone)]
112pub struct ClientCredentialsAuthorizationUrlParameterBuilder {
113 credential: ClientCredentialsAuthorizationUrlParameters,
114}
115
116impl ClientCredentialsAuthorizationUrlParameterBuilder {
117 pub fn new(client_id: impl AsRef<str>) -> Self {
118 Self {
119 credential: ClientCredentialsAuthorizationUrlParameters {
120 app_config: AppConfig::new(client_id.as_ref()),
121 state: None,
122 },
123 }
124 }
125
126 pub(crate) fn new_with_app_config(app_config: AppConfig) -> Self {
127 Self {
128 credential: ClientCredentialsAuthorizationUrlParameters {
129 app_config,
130 state: None,
131 },
132 }
133 }
134
135 pub fn with_client_id<T: AsRef<str>>(&mut self, client_id: T) -> IdentityResult<&mut Self> {
136 self.credential.app_config.client_id = Uuid::try_parse(client_id.as_ref())?;
137 Ok(self)
138 }
139
140 pub fn with_redirect_uri(&mut self, redirect_uri: Url) -> &mut Self {
141 self.credential.app_config.redirect_uri = Some(redirect_uri);
142 self
143 }
144
145 pub fn with_tenant<T: AsRef<str>>(&mut self, tenant: T) -> &mut Self {
147 self.credential.app_config.authority = Authority::TenantId(tenant.as_ref().to_owned());
148 self
149 }
150
151 pub fn with_authority<T: Into<Authority>>(&mut self, authority: T) -> &mut Self {
152 self.credential.app_config.authority = authority.into();
153 self
154 }
155
156 pub fn with_state<T: AsRef<str>>(&mut self, state: T) -> &mut Self {
157 self.credential.state = Some(state.as_ref().to_owned());
158 self
159 }
160
161 pub fn build(&self) -> ClientCredentialsAuthorizationUrlParameters {
162 self.credential.clone()
163 }
164
165 pub fn url(&self) -> IdentityResult<Url> {
166 self.credential.url()
167 }
168
169 pub fn with_client_secret(
170 self,
171 client_secret: impl AsRef<str>,
172 ) -> ClientSecretCredentialBuilder {
173 ClientSecretCredentialBuilder::new_with_client_secret(
174 client_secret,
175 self.credential.app_config,
176 )
177 }
178
179 pub fn with_client_assertion(
180 self,
181 signed_assertion: impl AsRef<str>,
182 ) -> ClientAssertionCredentialBuilder {
183 ClientAssertionCredentialBuilder::new_with_signed_assertion(
184 signed_assertion,
185 self.credential.app_config,
186 )
187 }
188
189 #[cfg(feature = "openssl")]
190 pub fn with_client_x509_certificate(
191 self,
192 _client_secret: impl AsRef<str>,
193 x509: &X509Certificate,
194 ) -> IdentityResult<ClientCertificateCredentialBuilder> {
195 ClientCertificateCredentialBuilder::new_with_certificate(x509, self.credential.app_config)
196 }
197}