Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Basic draft
  • Loading branch information
abhidnya13 committed Oct 14, 2019
commit a3b2af8ec8e05dc76c04083a9fe6ba79fcb1f0d0
4 changes: 2 additions & 2 deletions msal/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def __init__(
client_credential=None, authority=None, validate_authority=True,
token_cache=None,
verify=True, proxies=None, timeout=None,
client_claims=None):
client_claims=None, is_b2c=False):
"""Create an instance of application.

:param client_id: Your app has a client_id after you register it on AAD.
Expand Down Expand Up @@ -140,7 +140,7 @@ def __init__(
self.timeout = timeout
self.authority = Authority(
authority or "https://login.microsoftonline.com/common/",
validate_authority, verify=verify, proxies=proxies, timeout=timeout)
validate_authority, verify=verify, proxies=proxies, timeout=timeout, is_b2c=is_b2c)
# Here the self.authority is not the same type as authority in input
self.token_cache = token_cache or TokenCache()
self.client = self._build_client(client_credential, self.authority)
Expand Down
44 changes: 27 additions & 17 deletions msal/authority.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import re
import logging
try:
from urllib.parse import urlparse
except ImportError: # Fall back to Python 2
from urlparse import urlparse

import requests

Expand All @@ -24,7 +28,7 @@ class Authority(object):
TODO: It will also cache the previously-validated authority instances.
"""
def __init__(self, authority_url, validate_authority=True,
verify=True, proxies=None, timeout=None,
verify=True, proxies=None, timeout=None, is_b2c=False
):
"""Creates an authority instance, and also validates it.

Expand All @@ -37,18 +41,20 @@ def __init__(self, authority_url, validate_authority=True,
self.verify = verify
self.proxies = proxies
self.timeout = timeout
canonicalized, self.instance, tenant = canonicalize(authority_url)
tenant_discovery_endpoint = (
'https://{}/{}{}/.well-known/openid-configuration'.format(
self.instance,
tenant,
"" if tenant == "adfs" else "/v2.0" # the AAD v2 endpoint
authority , self.instance, tenant = canonicalize(authority_url)
if(tenant != "adfs" and (not is_b2c) and validate_authority
and self.instance not in WELL_KNOWN_AUTHORITY_HOSTS):
payload = instance_discovery(
"https://{}{}/oauth2/v2.0/authorize".format(
self.instance, authority.path),
verify=verify, proxies=proxies, timeout=timeout)
else:
tenant_discovery_endpoint = (
'https://{}{}{}/.well-known/openid-configuration'.format(
self.instance,
authority.path, # In B2C scenario, it is "/tenant/policy"
"" if tenant == "adfs" else "/v2.0" # the AAD v2 endpoint
))
if (tenant != "adfs" and validate_authority
and self.instance not in WELL_KNOWN_AUTHORITY_HOSTS):
tenant_discovery_endpoint = instance_discovery(
canonicalized + "/oauth2/v2.0/authorize",
verify=verify, proxies=proxies, timeout=timeout)
openid_config = tenant_discovery(
tenant_discovery_endpoint,
verify=verify, proxies=proxies, timeout=timeout)
Expand All @@ -57,6 +63,7 @@ def __init__(self, authority_url, validate_authority=True,
self.token_endpoint = openid_config['token_endpoint']
_, _, self.tenant = canonicalize(self.token_endpoint) # Usually a GUID
self.is_adfs = self.tenant.lower() == 'adfs'
self.is_b2c = is_b2c

def user_realm_discovery(self, username):
resp = requests.get(
Expand All @@ -70,15 +77,18 @@ def user_realm_discovery(self, username):
# "federation_protocol", "cloud_audience_urn",
# "federation_metadata_url", "federation_active_auth_url", etc.

def canonicalize(url):
def canonicalize(authority_url):
# Returns (canonicalized_url, netloc, tenant). Raises ValueError on errors.
match_object = re.match(r'https://([^/]+)/([^/?#]+)', url.lower())
if not match_object:
authority = urlparse(authority_url)
parts = authority.path.split("/")
if authority.scheme != "https" or len(parts) < 2 or not parts[1]:
raise ValueError(
"Your given address (%s) should consist of "
"an https url with a minimum of one segment in a path: e.g. "
"https://login.microsoftonline.com/<tenant_name>" % url)
return match_object.group(0), match_object.group(1), match_object.group(2)
"https://login.microsoftonline.com/<tenant> "
"or https://<tenant_name>.b2clogin.com/<tenant_name>.onmicrosoft.com/policy"
% authority_url)
return authority, authority.netloc, parts[1]

def instance_discovery(url, response=None, **kwargs):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since B2C does not do Instance Discovery at all, this PR should not need to change this helper.

Regardless of the B2C api interface, this helper was recently updated as part of an improvement for non-B2C scenarios. Now that change was lost, possibly caused by an improper merge between the dev branch and your local branch? We can fix that, by either cherry-pick those lost commits back, or it might actually be easier to branch off the latest dev, and then add the needed changes on top of it.

# Returns tenant discovery endpoint
Expand Down