403 Authorization_RequestОтклонено при попытке чтения пользователей - PullRequest
1 голос
/ 05 июля 2019

Я пытаюсь получить список всех пользователей в каталоге Exchange с помощью конечной точки API https://graph.microsoft.com/v1.0/users/ Это работает с помощью Graph Explorer , я получаю предварительный просмотр со списком из 100 действительных результатов.

Однако при доступе к той же конечной точке из моего приложения Python, входе в систему с тем же пользователем, я получаю следующий ответ:

{'error': {'code': 'Authorization_RequestDenied', 'message': 'Insufficient privileges to complete the operation.', 'innerError': {'request-id': '6924dba1-83ee-4865-9dcf-76b6cafcb808', 'date': '2019-07-04T21:08:28'}}}

Это код Python, который я использую, большая часть которого скопирована из python-sample-console-app

CLIENT_ID = '765bdd8d-b33d-489b-a039-3cdf41223aa4'

AUTHORITY_URL = 'https://login.microsoftonline.com/common'
RESOURCE = 'https://graph.microsoft.com'
API_VERSION = 'v1.0'

import base64
import mimetypes
import os
import urllib
import webbrowser

from adal import AuthenticationContext
import pyperclip
import requests

def device_flow_session(client_id, auto=False):
    """Obtain an access token from Azure AD (via device flow) and create
    a Requests session instance ready to make authenticated calls to
    Microsoft Graph.
    client_id = Application ID for registered "Azure AD only" V1-endpoint app
    auto      = whether to copy device code to clipboard and auto-launch browser
    Returns Requests session object if user signed in successfully. The session
    includes the access token in an Authorization header.
    User identity must be an organizational account (ADAL does not support MSAs).
    """
    ctx = AuthenticationContext(AUTHORITY_URL, api_version=None)
    device_code = ctx.acquire_user_code(RESOURCE, client_id)

    # display user instructions
    if auto:
        pyperclip.copy(device_code['user_code']) # copy user code to clipboard
        webbrowser.open(device_code['verification_url']) # open browser
        print(f'The code {device_code["user_code"]} has been copied to your clipboard, '
              f'and your web browser is opening {device_code["verification_url"]}. '
              'Paste the code to sign in.')
    else:
        print(device_code['message'])

    token_response = ctx.acquire_token_with_device_code(RESOURCE,
                                                        device_code,
                                                        client_id)
    if not token_response.get('accessToken', None):
        return None

    session = requests.Session()
    session.headers.update({'Authorization': f'Bearer {token_response["accessToken"]}',
                            'SdkVersion': 'sample-python-adal',
                            'x-client-SKU': 'sample-python-adal'})
    return session

def api_endpoint(url):
    """Convert a relative path such as /me/photo/$value to a full URI based
    on the current RESOURCE and API_VERSION settings in config.py.
    """
    if urllib.parse.urlparse(url).scheme in ['http', 'https']:
        return url # url is already complete
    return urllib.parse.urljoin(f'{RESOURCE}/{API_VERSION}/',
url.lstrip('/'))

session = device_flow_session(CLIENT_ID, True)
users = session.get(api_endpoint('users'))
print(users.json())

У меня также есть следующие разрешения, установленные на портале Microsoft Azure: permissions

В частности, User.ReadBasic.All должно быть достаточно, чтобы получить список всех пользователей только с базовыми свойствами, такими как имя и адрес электронной почты, но он по-прежнему не работает.

Видимо, в проблеме отсутствовало "согласие пользователя". Здесь происходит некоторая странность, потому что теоретически страница входа должна автоматически запрашивать согласие пользователя для всех настроенных разрешений API. После еще нескольких попыток я нашел следующие решения:

Решение 1

  • Зарегистрируйте новое приложение на portal.azure.com
  • Заранее добавьте необходимые настройки и разрешения API
  • При изменении необходимых разрешений API пользователь больше не запрашивается
  • Повторно создайте приложение на portal.azure.com в любое время, когда вам нужно получить доступ к новому API, и соответственно измените идентификатор приложения в вашем приложении

Решение 2

  • Обнаружить ошибку Authorization_RequestDenied
  • В этом случае откройте окно браузера со специальным URL-адресом для запроса согласия пользователя
  • Попросить пользователя перезапустить приложение после того, как он успешно вошел в систему и дал согласие
  • Вот соответствующий код
CONSENT_URL = f'https://login.microsoftonline.com/common/oauth2/authorize?client_id={CLIENT_ID}&response_type=code&response_mode=query&resource=https://graph.microsoft.com&state=12345&prompt=consent'
#...
response = session.get(api_endpoint('users')).json()
if 'error' in response and response['error']['code'] == 'Authorization_RequestDenied':
    print("Access denied. Consent page has been opened in the webbrowser. Please give user consent, then start the script again!")
    webbrowser.open(CONSENT_URL)
    sys.exit(1)

1 Ответ

0 голосов
/ 05 июля 2019

При первом использовании обозревателя графиков у вас должно быть запрошено согласие на использование обозревателя.

Поэтому, когда вы входите в систему с помощью приложения, зарегистрированного на портале Azure, у вас также должен быть запрос на согласие.использовать приложение.Но если вы добавите / обновите разрешения после согласия.Вы должны дать согласие еще раз.

enter image description here

Вы можете принудительно подтвердить свое согласие с помощью URL-запроса, добавить & prompt = согласие с URL-адресом запроса на аутентификацию.

Или вы просто даете согласие от имени всех пользователей в этом каталоге.Предоставление согласия администратора всем пользователям означает, что конечным пользователям не будет отображаться экран согласия при использовании приложения.

enter image description here

...