Skip to content
This repository has been archived by the owner on Sep 29, 2023. It is now read-only.

Commit

Permalink
Merge pull request #106 from AzureAD/release-0.4.7
Browse files Browse the repository at this point in the history
Release 0.4.7
  • Loading branch information
rayluo authored Aug 28, 2017
2 parents 03269cf + e80b83a commit 582fc11
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 70 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ script:
deploy:
- # test pypi
provider: pypi
distributions: sdist
distributions: "sdist bdist_wheel"
server: https://test.pypi.org/legacy/
user: "nugetaad"
password:
Expand All @@ -28,7 +28,7 @@ deploy:

- # production pypi
provider: pypi
distributions: sdist
distributions: "sdist bdist_wheel"
user: "nugetaad"
password:
secure: Wm2jGolFLm/wrfSPklf9gYdWiTK7ycGr+Qa0voVmFEJkW69PRC5bCibJI3POK1DqTBmQn7gi5G0s117PoLlXvK9lqwMaDL6Yf/ro7YnMU9pBopoB/zWMxWYZeBJVugmTGKuTkbUiQBzL2h0EnaQvvyrEDiLGrYrYEgLUSuR5AVTlvYKk1XBAAhvh8hu8JjgQQugN2ne6ZR9aBjCap0fzdTs3vhad/OQx+iH8YR8UTl4ruszdoL95CDtFmKdIkwg0qgIB65MqC6XAQ2tvhyMDHXZMMafE0NQwUwm2d+sqinCfHLNkb5bVBS0M8syrYCS8xr6Ccnt0PM1+nNFm83bu1w+HaMwKWD2IaU26QH8H7djc7mO1XmRmMSxQ1EjR313YyF534+uiLBlJWB8DOfN4r3/lqg6e44CY0impiT7NnT47bUqaoglew5HB0FgrrtGDrDlLa7zf+RHyb2BhqeqlTR1s0nnzsmzQMdxaHXvCbzYPqg3PUdwLHGBks90tXhA0zUg/3XQfb7v17Lx1byRufvsWWYXUZwLI6H8CCvWtWFvJ3TSPPBR/5LjaICVtt2g3Uv2xrG3weCIO52G7WQ6pIpOyiRsYkUAIXLi2UNsv4LlpNxNObNgL7FNfrNR/tEs8+SdbAkaf2jrFfn+Sk7v4pdPd4og7YXWAE2R/ge9nsJ4=
Expand Down
66 changes: 8 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,71 +30,21 @@ For more context, starts with this [stackoverflow thread](http://stackoverflow.c

In order to use this token acquisition method, you need to configure a service principal. Please follow [this walkthrough](https://azure.microsoft.com/en-us/documentation/articles/resource-group-create-service-principal-portal/).

See the [sample](./sample/client_credentials_sample.py).
```python
import adal

context = adal.AuthenticationContext('https://login.microsoftonline.com/ABCDEFGH-1234-1234-1234-ABCDEFGHIJKL')
RESOURCE = '00000002-0000-0000-c000-000000000000' #AAD graph resource
token = context.acquire_token_with_client_credentials(
RESOURCE,
"http://PythonSDK",
"Key-Configured-In-Portal")
```
Find the `Main logic` part in the [sample](sample/client_credentials_sample.py#L46-L55).

### Acquire Token with client certificate
A service principal is also required. See the [sample](./sample/certificate_credentials_sample.py).
```python
import adal
context = adal.AuthenticationContext('https://login.microsoftonline.com/ABCDEFGH-1234-1234-1234-ABCDEFGHIJKL')
RESOURCE = '00000002-0000-0000-c000-000000000000' #AAD graph resource
token = context.acquire_token_with_client_certificate(
RESOURCE,
"http://PythonSDK",
'yourPrivateKeyFileContent',
'thumbprintOfPrivateKey')
```
A service principal is also required.
Find the `Main logic` part in the [sample](sample/certificate_credentials_sample.py#L55-L64).

### Acquire Token with Refresh Token
See the [sample](./sample/refresh_token_sample.py).
```python
import adal
context = adal.AuthenticationContext('https://login.microsoftonline.com/ABCDEFGH-1234-1234-1234-ABCDEFGHIJKL')
RESOURCE = '00000002-0000-0000-c000-000000000000' #AAD graph resource
token = context.acquire_token_with_username_password(
RESOURCE,
'yourName',
'yourPassword',
'yourClientIdHere')

refresh_token = token['refreshToken']
token = context.acquire_token_with_refresh_token(
refresh_token,
'yourClientIdHere',
RESOURCE)
```
Find the `Main logic` part in the [sample](sample/refresh_token_sample.py#L47-L69).

### Acquire Token with device code
See the [sample](./sample/device_code_sample.py).
```python
context = adal.AuthenticationContext('https://login.microsoftonline.com/ABCDEFGH-1234-1234-1234-ABCDEFGHIJKL')
RESOURCE = '00000002-0000-0000-c000-000000000000' #AAD graph resource
code = context.acquire_user_code(RESOURCE, 'yourClientIdHere')
print(code['message'])
token = context.acquire_token_with_device_code(RESOURCE, code, 'yourClientIdHere')
```
Find the `Main logic` part in the [sample](sample/device_code_sample.py#L49-L54).

### Acquire Token with authorization code
See the [sample](./sample/website_sample.py) for a complete bare bones web site that makes use of the code below.
```python
context = adal.AuthenticationContext('https://login.microsoftonline.com/ABCDEFGH-1234-1234-1234-ABCDEFGHIJKL')
RESOURCE = '00000002-0000-0000-c000-000000000000' #AAD graph resource
return context.acquire_token_with_authorization_code(
'yourCodeFromQueryString',
'yourWebRedirectUri',
RESOURCE,
'yourClientId',
'yourClientSecret')
```
Find the `Main logic` part in the [sample](sample/website_sample.py#L107-L115) for a complete bare bones web site that makes use of the code below.


## Samples and Documentation
We provide a full suite of [sample applications on GitHub](https://github.com/azure-samples?utf8=%E2%9C%93&q=active-directory&type=&language=) and an [Azure AD developer landing page](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-developers-guide) to help you get started with learning the Azure Identity system. This includes tutorials for native clients and web applications. We also provide full walkthroughs for authentication flows such as OAuth2, OpenID Connect and for calling APIs such as the Graph API.
Expand Down
2 changes: 1 addition & 1 deletion adal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

# pylint: disable=wrong-import-position

__version__ = '0.4.6'
__version__ = '0.4.7'

import logging

Expand Down
6 changes: 6 additions & 0 deletions adal/cache_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ def _create_entry_from_refresh(self, entry, refresh_response):
new_entry = copy.deepcopy(entry)
new_entry.update(refresh_response)

# It is possible the response payload has no 'resource' field, like in ADFS, so we manually
# fill it here. Note, 'resource' is part of the token cache key, so we have to set it to avoid
# corrupting the cache.
if 'resource' not in refresh_response:
new_entry['resource'] = self._resource

if entry[TokenResponseFields.IS_MRRT] and self._authority != entry[TokenResponseFields._AUTHORITY]:
new_entry[TokenResponseFields._AUTHORITY] = self._authority

Expand Down
2 changes: 2 additions & 0 deletions sample/certificate_credentials_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def get_private_key(filename):
#uncomment for verbose logging
turn_on_logging()

### Main logic begins
context = adal.AuthenticationContext(authority_url, api_version=None)
key = get_private_key(sample_parameters['privateKeyFile'])

Expand All @@ -60,6 +61,7 @@ def get_private_key(filename):
sample_parameters['clientId'],
key,
sample_parameters['thumbprint'])
### Main logic ends

print('Here is the token:')
print(json.dumps(token, indent=2))
2 changes: 2 additions & 0 deletions sample/client_credentials_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def turn_on_logging():
#uncomment for verbose log
#turn_on_logging()

### Main logic begins
context = adal.AuthenticationContext(
authority_url, validate_authority=sample_parameters['tenant'] != 'adfs',
api_version=None)
Expand All @@ -51,6 +52,7 @@ def turn_on_logging():
RESOURCE,
sample_parameters['clientId'],
sample_parameters['clientSecret'])
### Main logic ends

print('Here is the token:')
print(json.dumps(token, indent=2))
2 changes: 2 additions & 0 deletions sample/device_code_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ def turn_on_logging():
#uncomment for verbose logging
#turn_on_logging()

### Main logic begins
context = adal.AuthenticationContext(authority_url, api_version=None)
code = context.acquire_user_code(RESOURCE, clientid)
print(code['message'])
token = context.acquire_token_with_device_code(RESOURCE, code, clientid)
### Main logic ends

print('Here is the token from "{}":'.format(authority_url))
print(json.dumps(token, indent=2))
Expand Down
7 changes: 6 additions & 1 deletion sample/refresh_token_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def turn_on_logging():
#uncomment for verbose log
#turn_on_logging()

### Main logic begins
context = adal.AuthenticationContext(
authority_url, validate_authority=sample_parameters['tenant'] != 'adfs',
api_version=None)
Expand All @@ -61,7 +62,11 @@ def turn_on_logging():
token = context.acquire_token_with_refresh_token(
refresh_token,
sample_parameters['clientid'],
RESOURCE)
RESOURCE,
# client_secret="your_secret" # This is needed when using Confidential Client,
# otherwise you will encounter an invalid_client error.
)
### Main logic ends

print('Here is the token acquired from the refreshing token')
print(json.dumps(token, indent=2))
2 changes: 2 additions & 0 deletions sample/website_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,15 @@ def _acquire_token(self):
cookie = Cookie.SimpleCookie(self.headers["Cookie"])
if state != cookie['auth_state'].value:
raise ValueError('state does not match')
### Main logic begins
auth_context = AuthenticationContext(authority_url, api_version=None)
return auth_context.acquire_token_with_authorization_code(
code,
REDIRECT_URI,
RESOURCE,
sample_parameters['clientId'],
sample_parameters['clientSecret'])
### Main logic ends

def _send_response(self, message, is_ok=True):
self.send_response(200 if is_ok else 400)
Expand Down
46 changes: 38 additions & 8 deletions tests/test_refresh_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,31 +41,61 @@
import mock

import adal
from adal.authentication_context import AuthenticationContext
from adal.authentication_context import AuthenticationContext, TokenCache
from tests import util
from tests.util import parameters as cp

class TestRefreshToken(unittest.TestCase):
def setUp(self):
self.response_options = { 'refreshedRefresh' : True }
self.response = util.create_response(self.response_options)
self.wire_response = self.response['wireResponse']

@httpretty.activate
def test_happy_path_with_resource_client_secret(self):
tokenRequest = util.setup_expected_refresh_token_request_response(200, self.wire_response, self.response['authority'], self.response['resource'], cp['clientSecret'])
response_options = { 'refreshedRefresh' : True }
response = util.create_response(response_options)
wire_response = response['wireResponse']
tokenRequest = util.setup_expected_refresh_token_request_response(200, wire_response, response['authority'], response['resource'], cp['clientSecret'])

context = adal.AuthenticationContext(cp['authorityTenant'])
def side_effect (tokenfunc):
return self.response['decodedResponse']
return response['decodedResponse']

context._acquire_token = mock.MagicMock(side_effect=side_effect)

token_response = context.acquire_token_with_refresh_token(cp['refreshToken'], cp['clientId'], cp['clientSecret'], cp['resource'])
self.assertTrue(
util.is_match_token_response(self.response['decodedResponse'], token_response),
util.is_match_token_response(response['decodedResponse'], token_response),
'The response did not match what was expected: ' + str(token_response)
)

@httpretty.activate
def test_happy_path_with_resource_adfs(self):
# arrange
# set up token refresh result
wire_response = util.create_response({
'refreshedRefresh' : True,
'mrrt': False
})['wireResponse']
new_resource = 'https://graph.local.azurestack.external/'
tokenRequest = util.setup_expected_refresh_token_request_response(200, wire_response, cp['authority'], new_resource)

# set up an existing token to be used for refreshing
existing_token = util.create_response({
'refreshedRefresh': True,
'mrrt': True
})['decodedResponse']
existing_token['_clientId'] = existing_token.get('_clientId') or cp['clientId']
existing_token['isMRRT'] = existing_token.get('isMRRT') or True
existing_token['_authority'] = existing_token.get('_authority') or cp['authorizeUrl']
token_cache = TokenCache(json.dumps([existing_token]))

# act
user_id = existing_token['userId']
context = adal.AuthenticationContext(cp['authorityTenant'], cache=token_cache)
token_response = context.acquire_token(new_resource, user_id, cp['clientId'])

# assert
tokens = [value for key, value in token_cache.read_items()]
self.assertEqual(2, len(tokens))
self.assertEqual({cp['resource'], new_resource}, set([x['resource'] for x in tokens]))

if __name__ == '__main__':
unittest.main()

0 comments on commit 582fc11

Please sign in to comment.