|
5 | 5 | from urlparse import urlparse |
6 | 6 | import logging |
7 | 7 |
|
8 | | -from .exceptions import MsalServiceError |
9 | | - |
10 | 8 |
|
11 | 9 | logger = logging.getLogger(__name__) |
12 | 10 |
|
|
28 | 26 | "b2clogin.cn", |
29 | 27 | "b2clogin.us", |
30 | 28 | "b2clogin.de", |
| 29 | + "ciamlogin.com", |
31 | 30 | ] |
| 31 | +_CIAM_DOMAIN_SUFFIX = ".ciamlogin.com" |
32 | 32 |
|
33 | 33 |
|
34 | 34 | class AuthorityBuilder(object): |
@@ -74,7 +74,8 @@ def __init__( |
74 | 74 | if isinstance(authority_url, AuthorityBuilder): |
75 | 75 | authority_url = str(authority_url) |
76 | 76 | authority, self.instance, tenant = canonicalize(authority_url) |
77 | | - self.is_adfs = tenant.lower() == 'adfs' |
| 77 | + is_ciam = self.instance.endswith(_CIAM_DOMAIN_SUFFIX) |
| 78 | + self.is_adfs = tenant.lower() == 'adfs' and not is_ciam |
78 | 79 | parts = authority.path.split('/') |
79 | 80 | self._is_b2c = any( |
80 | 81 | self.instance.endswith("." + d) for d in WELL_KNOWN_B2C_HOSTS |
@@ -103,13 +104,13 @@ def __init__( |
103 | 104 | % authority_url) |
104 | 105 | tenant_discovery_endpoint = payload['tenant_discovery_endpoint'] |
105 | 106 | else: |
106 | | - tenant_discovery_endpoint = ( |
107 | | - 'https://{}:{}{}{}/.well-known/openid-configuration'.format( |
108 | | - self.instance, |
109 | | - 443 if authority.port is None else authority.port, |
110 | | - authority.path, # In B2C scenario, it is "/tenant/policy" |
111 | | - "" if tenant == "adfs" else "/v2.0" # the AAD v2 endpoint |
112 | | - )) |
| 107 | + tenant_discovery_endpoint = authority._replace( |
| 108 | + path="{prefix}{version}/.well-known/openid-configuration".format( |
| 109 | + prefix=tenant if is_ciam and len(authority.path) <= 1 # Path-less CIAM |
| 110 | + else authority.path, # In B2C, it is "/tenant/policy" |
| 111 | + version="" if self.is_adfs else "/v2.0", |
| 112 | + ) |
| 113 | + ).geturl() # Keeping original port and query. Query is useful for test. |
113 | 114 | try: |
114 | 115 | openid_config = tenant_discovery( |
115 | 116 | tenant_discovery_endpoint, |
@@ -144,18 +145,28 @@ def user_realm_discovery(self, username, correlation_id=None, response=None): |
144 | 145 | return {} # This can guide the caller to fall back normal ROPC flow |
145 | 146 |
|
146 | 147 |
|
147 | | -def canonicalize(authority_url): |
| 148 | +def canonicalize(authority_or_auth_endpoint): |
148 | 149 | # Returns (url_parsed_result, hostname_in_lowercase, tenant) |
149 | | - authority = urlparse(authority_url) |
150 | | - parts = authority.path.split("/") |
151 | | - if authority.scheme != "https" or len(parts) < 2 or not parts[1]: |
152 | | - raise ValueError( |
153 | | - "Your given address (%s) should consist of " |
154 | | - "an https url with a minimum of one segment in a path: e.g. " |
155 | | - "https://login.microsoftonline.com/<tenant> " |
156 | | - "or https://<tenant_name>.b2clogin.com/<tenant_name>.onmicrosoft.com/policy" |
157 | | - % authority_url) |
158 | | - return authority, authority.hostname, parts[1] |
| 150 | + authority = urlparse(authority_or_auth_endpoint) |
| 151 | + if authority.scheme == "https": |
| 152 | + parts = authority.path.split("/") |
| 153 | + first_part = parts[1] if len(parts) >= 2 and parts[1] else None |
| 154 | + if authority.hostname.endswith(_CIAM_DOMAIN_SUFFIX): # CIAM |
| 155 | + # Use path in CIAM authority. It will be validated by OIDC Discovery soon |
| 156 | + tenant = first_part if first_part else "{}.onmicrosoft.com".format( |
| 157 | + # Fallback to sub domain name. This variation may not be advertised |
| 158 | + authority.hostname.rsplit(_CIAM_DOMAIN_SUFFIX, 1)[0]) |
| 159 | + return authority, authority.hostname, tenant |
| 160 | + # AAD |
| 161 | + if len(parts) >= 2 and parts[1]: |
| 162 | + return authority, authority.hostname, parts[1] |
| 163 | + raise ValueError( |
| 164 | + "Your given address (%s) should consist of " |
| 165 | + "an https url with a minimum of one segment in a path: e.g. " |
| 166 | + "https://login.microsoftonline.com/<tenant> " |
| 167 | + "or https://<tenant_name>.ciamlogin.com/<tenant> " |
| 168 | + "or https://<tenant_name>.b2clogin.com/<tenant_name>.onmicrosoft.com/policy" |
| 169 | + % authority_or_auth_endpoint) |
159 | 170 |
|
160 | 171 | def _instance_discovery(url, http_client, instance_discovery_endpoint, **kwargs): |
161 | 172 | resp = http_client.get( |
|
0 commit comments