|
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