2015-02-05 3 views
9

Я пытаюсь построить Ruby Служба Daemon для доступа к API-интерфейсу Office 365. В последнее время это стало возможным благодаря потоку OAuth 'client_credentials', как подробно описано в этом сообщении в блоге: http://blogs.msdn.com/b/exchangedev/archive/2015/01/22/building-demon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow.aspxOffice 365 Rest API - аутентификация недели демонов

Я изо всех сил пытаюсь создать действительный токен доступа. Маркер конечной точки возвращает мне JWT, однако при использовании этого маркера я получил 401 с этим сообщением:

The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2

Я понимаю, что поток client_credentials требует, чтобы вы представить X.509 сертификат, к сожалению, все примеры в блоге сообщение для C#.

Я использую сгенерированный self signed cert и закрытый ключ для выполнения утверждения клиента при запросе маркера. Я выполнил шаги в блоге, чтобы создать сертификат и обновить манифест, чтобы использовать этот сертификат.

Это рубин коды для справки:

def request_token 
    uri = URI.parse("https://login.windows.net/== TENANT-ID ==/oauth2/token?api-version=1.0") 
    https = Net::HTTP.new(uri.host, uri.port) 

    req = Net::HTTP::Post.new(uri.request_uri) 
    req.set_form_data(
    :grant_type => 'client_credentials', 
    :redirect_uri => 'http://spready.dev', 
    :resource  => 'https://outlook.office365.com/', 
    :client_id  => '== Client ID ==', 
    :client_secret => '== Client secret ==' 
) 

    https.use_ssl = true 
    https.cert = client_cert 
    https.key = client_key 
    https.verify_mode = OpenSSL::SSL::VERIFY_PEER 

    resp = https.start { |cx| cx.request(req) } 

    @access_token = JSON.parse(resp.body) 
end 

Очевидно, что я удалил некоторые биты информации для обеспечения безопасности. Хотя это рубин, вы можете видеть, что я использую свой сертификат для проверки клиента с помощью SSL-соединения.

Вот еще некоторые детали на ошибку:

"x-ms-diagnostics" => "2000010; 
    reason=\"The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2.\"; 
    error_category=\"insufficient_auth_strength\"", 
"x-diaginfo"=>"AM3PR01MB0662", 
"x-beserver"=>"AM3PR01MB0662" 

Любая помощь будет признателен.


Редактировать

Для тех, кто стремится сделать что-то подобное в Руби вот Сущность кода я использую: https://gist.github.com/NGMarmaduke/a088943edbe4e703129d

В примере используется среда Rails, но она должна быть достаточно легко вырезать конкретные бит Rails.

Не забудьте заменить ВАШИ ИДЕНТИФИКАТОР КЛИЕНТА, TENANT_ID и CERT_THUMBPRINT с правильными значениями и указать путь сертификата и методы ключа клиента к правильному пути к файлу.

Затем вы можете сделать что-то вроде этого:

mailbox = OfficeAPI.new("[email protected]") 
messages = mailbox.request_messages 
+0

Эй @ Ник, вы когда-нибудь заставляли это работать? Я бы хотел увидеть ваш код. Я пытаюсь сделать что-то подобное в Ruby и не могу заставить его работать даже после попытки сделать то, что сказал Джейсон. –

+0

Эй, Джоэл, просто добавил еще несколько вопросов к вопросу с сущностью моего кода. –

+0

Perfect. Благодаря тонну! –

ответ

9

Вместо того, чтобы client_secret в вашем теле запроса, вам нужно client_assertion. Это немного сложнее, но по этой причине вам нужен этот сертификат.

В принципе, вам необходимо создать веб-маркер JSON и подписать его сертификатом с использованием хэша SHA256. Маркер будет выглядеть примерно так:

Заголовок:

{ 
    "alg": "RS256", 
    "x5t": "..." // THUMBPRINT of Cert 
} 

Payload:

{ 
    "aud": "https:\\/\\/login.windows.net\\/<The logged in user's tenant ID>\\/oauth2\\/token", 
    "exp": 1423168488, 
    "iss": "YOUR CLIENT ID", 
    "jti": "SOME GUID YOU ASSIGN", 
    "nbf": 1423167888, 
    "sub": "YOUR CLIENT ID" 
} 

Если вы все еще со мной, теперь нужно base64-кодирования обеих частей (отдельно), затем объедините их с помощью «.».Итак, теперь у вас должно быть:

base64_header.base64_payload 

Теперь вы берете эту строку и подписываете ее с помощью своего сертификата, используя хэш SHA256. Тогда base64-кодирование результата этого, URL-кодирования его, а затем добавить к строке, так что теперь у вас есть:

base64_header.base64_payload.base64_signature 

Наконец, включить это в вашем посте маркеров конечной точки в качестве параметра client_assertion, а также включить параметр client_assertion_type установлен в "урну: IETF: Титулы: OAuth: клиент-утверждение типа: JWT-носителя":

req.set_form_data(
    :grant_type => 'client_credentials', 
    :redirect_uri => 'http://spready.dev', 
    :resource  => 'https://outlook.office365.com/', 
    :client_id  => '== Client ID ==', 
    :client_assertion_type => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer', 
    :client_assertion => 'base64_header.base64_payload.base64_signature' 
) 

Я надеюсь, что помогает! Все это основано на моих исследованиях, как это делает ADAL, и я не тестировал его сам в Ruby.

+4

Отлично, спасибо снова Джейсону. Было бы неплохо документировать это для людей, не развивающихся с помощью ADAL. Возможно, обновите документ учетных данных клиента Azure: https://msdn.microsoft.com/en-us/library/azure/dn645543.aspx –

+1

@NickMaher Этот документ обязательно должен быть обновлен. Я сделал запрос в Microsoft об этом. –

+0

@Jason, один вопрос: зачем нужен этот сертификат при вызове API Office365, но он не нужен при вызове Graph API? Я могу выполнить аутентификацию с помощью 'clientId' и' clientSecret' с потоком предоставления учетных данных клиента в Graph API, но не в Office365. Почему это? –

0

Просто некоторые дополнения: Заявка аудитории в утверждении совпадает с конечной точкой, которую вы адресуете с помощью запроса на токен. Как правильно определил Джейсон, это конечная точка маркера AAD: https://login.windows.net/ {арендатор, которому нужен токен приложения для// oauth2/token. Также nbf и exp - время, когда вы создали утверждение в эпоху unix epoche, например. в .net вы бы сделали что-то вроде «WebConvert.EpocTime (DateTime.UtcNow)». Для «не раньше» (nbf) возможно вычесть буфер для перекоса часов, например. 5 минут; и для истечения в (exp) добавить некоторое время, например. 15 минут (так что утверждение остается в силе на то время).

Вот стельку след маркера запроса (сырой): POST https://login.windows.net/0e49ef1f-ca07-45f1-b4c0-ac9409d3e576/oauth2/token HTTP/1.1 Content-Type: применение/х-WWW-форм-urlencoded клиент-запрос-ID: a8108f88-275b-424d- ac28-f675aabe548e возврата клиент-запрос-ID: истинный х-клиент-SKU: .NET х-клиент-Ver: 2.12.0.0 х-клиент-CPU: x64 х-клиента ОС: Microsoft Windows NT 6.2.9200.0 Хост: login.windows.net Контент-длина: 983 Ожидаем: 100-продолжить Подключение: Keep-Alive

ресурс = HTTPS% 3A% 2F% 2F% 2Fgraph.windows.net & client_id = f17bb8a5-2bef-4ad5-a83f-cd7113449fc2 & client_assertion_type = урна% 3Aietf% 3Aparams% 3Aoauth% 3Aclient-утверждение типа% 3Ajwt-носителем & client_assertion = eyJhbGciOiJSUzI1NiIsIng1dCI6ImY4S2JVY0xtMnItS2s4b1Z3ZVZYTFU0NzhJcyJ9.eyJhdWQiOiJodHRwczpcL1wvbG9naW4ud2luZG93cy5uZXRcLzBlNDllZjFmLWNhMDctNDVmMS1iNGMwLWFjOTQwOWQzZTU3Nlwvb2F1dGgyXC90b2tlbiIsImV4cCI6MTQyMjk4NDMzNSwiaXNzIjoiZjE3YmI4YTUtMmJlZi00YWQ1LWE4M2YtY2Q3MTEzNDQ5ZmMyIiwianRpIjoiZTI3OTA5YTctZGYwMC00NjBhLTlmZjctOGZkNDExOWVmNTYzIiwibmJmIjoxNDIyOTgzNzM1LCJzdWIiOiJmMTdiYjhhNS0yYmVmLTRhZDUtYTgzZi1jZDcxMTM0NDlmYzIifQ.g9bo4-lxpNJ4kEOMuQxODU-5iakwSVIzyRQEPLdbpuNn_XD4lcvt2yBIWT12EQaUVKkMyqFrDiIh4Oav565-Po7HfhmSPF3URXVj8Kx5lx17Zh0nWiaNkRXEi1vhwswsfjm1o-8B8LGUJTtT6JXTognrueuSL1aEE_-4qSG1y74aoc949Un1pQCjwuBtao4vs4CPJLu9Y9mVbirVRRtiIfxkUMmzf6yfMtuhugoGmrvUYntUo4x 6N2fu4LxGjuIs7czyrMMAmDRo-XK4sAhDo5uof10HKb8ETEU8mhObwNZcz86MYHWbZm3Z_HDOwzC9kA_tp6hWqmlJ3c-gLg5VXA & grant_type = client_credentials

Надеется, что это помогает! Удачи!

Matthias

+1

Также обратите внимание: вы можете убедиться, что ваше утверждение верное, используя http://jwt.calebb.net и вставьте кодированное значение base64url, которое вы генерируете/отправляете там. Он должен успешно показывать контент, как в приведенном выше примере Джейсона. –

4

Мне просто удалось заставить это работать, поэтому я подумал, что я брошу еще один совет в микс.Все статьи инструкций говорят, что вы должны добавить свой сертификат в файл манифеста. У меня была проблема с этим, но вот то, что я сделал это, наконец, сделал это работает:

  • В лазури, перейдите в раздел Настройки> Сертификаты управления
  • Загрузить открытый ключ как .cer файл (Google вокруг, если вы не не знаю, как его преобразовать). Это должен быть двоичный файл, в который встроен ваш текстовый редактор.
  • Теперь, когда он загружен, Microsoft предоставит вам отпечаток. Он находится в столбце «Отпечаток». Но, это в гексагоне, а не base64. Таким образом, преобразовать его так:

    # Hint: use your actual thumbprint, not this fake one 
    echo '5292850026FADB09700E7D6C1BCB1CD1F3270BCC' | xxd -r -p | base64 
    
  • Наконец, используйте эту base64 закодированный отпечаток пальца в качестве значения для x5t в заголовке JSON.

+0

Герм, я вижу отпечаток, но колонка недостаточно широка, поэтому она сокращает ее и добавляет эллипсы. Нет очевидного способа расширить информацию ... Идеи? – stu

+0

неважно, я получил его ... openssl x509 -in server.cer -fingerprint -noout | tr -d ':' | awk -F "=" '{print $ 2}' | xxd -r -p | base64 – stu

Смежные вопросы