2015-02-05 8 views
9

Próbuję utworzyć usługę Daemon usługi Ruby, aby uzyskać dostęp do interfejsu API usługi Office 365. Niedawno stało się to możliwe dzięki przepływowi "client_credentials" protokołu OAuth, tak jak to opisano w tym poście: 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.aspxInterfejs API usługi Office 365 - Uwierzytelnianie tygodnia demona

Próbuję wygenerować ważny token dostępu. Punkt końcowy znak zwraca mi JWT jednak podczas korzystania z tego tokenu Otrzymałem 401 z tej wiadomości:

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

Rozumiem, że przepływ client_credentials wymaga cię przedstawić cert X.509, niestety wszystkie przykłady w blogu post są dla C#.

Używam wygenerowanego samopodpisanego certyfikatu i klucza prywatnego do wykonania asercji klienta podczas żądania tokena. Postępowałem zgodnie z instrukcjami w poście na blogu, aby wygenerować certyfikat i zaktualizować manifest, aby korzystać z tego certyfikatu.

Jest to kod Ruby dla odniesienia:

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 

Oczywiście usunąłem niektóre bity informacji dla bezpieczeństwa. Nawet jeśli jest to rubin, widzisz, że używam mojego certyfikatu do sprawdzania poprawności klienta za pomocą połączenia SSL.

Oto kilka infomation od błędu:

"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" 

Każda pomoc będzie docenić.


Edit

Dla innych, którzy chcą zrobić coś podobnego w Ruby oto Streszczenie kod używam: https://gist.github.com/NGMarmaduke/a088943edbe4e703129d

Przykład wykorzystuje środowisko Rails, ale powinien być dość łatwe do wytnij specyficzne bity Rails.

Należy pamiętać o zastąpieniu IDENTYFIKATORA KLIENTA, TENANT_ID i CERT_THUMBPRINT poprawnymi wartościami i wskaż ścieżkę certyfikatu i metody klucza klienta do prawej ścieżki pliku.

Następnie można zrobić coś takiego:

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

Hej, który pomógł ci kiedyś zadzwonić? Chciałbym zobaczyć twój kod. Próbuję zrobić coś podobnego w Ruby i nie mogę sprawić, żeby działało, nawet po próbie wykonania tego, o czym mówił Jason. –

+0

Hej Joel, właśnie dodałem trochę więcej szczegółów do pytania, z istotą mojego kodu –

+0

Perfect. Dzięki za tonę! –

Odpowiedz

9

zamiast client_secret w organizmie żądanie, trzeba client_assertion. Jest to nieco bardziej skomplikowane, ale jest to powód, dla którego potrzebujesz tego certyfikatu.

Zasadniczo musisz zbudować token sieciowy JSON i podpisać go za pomocą certyfikatu, używając skrótu SHA256. Token będzie wyglądać mniej więcej tak:

Header:

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

Ładowność:

{ 
    "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" 
} 

Jeśli nadal jesteś ze mną, teraz trzeba base64 zakodować oba kawałki (oddzielnie), a następnie połączyć je znakiem ".".Teraz powinieneś już:

base64_header.base64_payload 

Teraz weź ten napis i podpisz go za pomocą certyfikatu, używając skrótu SHA256. Następnie base64 zakodować wynik tego, url zakodować, a potem dołącza do łańcucha, więc teraz masz:

base64_header.base64_payload.base64_signature 

Wreszcie, to ten w poście do tokenu końcowego jako parametr client_assertion, a także to parametr client_assertion_type ustawiony na "urn: IETF: params: OAuth: o wolność typu klient: JWT nosiciel":

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' 
) 

mam nadzieję, że pomoże! Wszystko opiera się na moich badaniach tego, jak robi to ADAL i sam tego nie przetestowałem w Ruby.

+4

Idealne, jeszcze raz dziękuję Jason. Dobrym pomysłem byłoby udokumentowanie tego dla osób, które nie pracują z ADAL. Ewentualnie zaktualizuj dokument poświadczeń klienta Azure AD tutaj: https://msdn.microsoft.com/en-us/library/azure/dn645543.aspx –

+1

@NickMaher Ten dokument powinien zdecydowanie zostać zaktualizowany. Poprosiłem o to Microsoft. –

+0

@Jason, jedno pytanie: dlaczego ten certyfikat jest potrzebny podczas wywoływania interfejsu API Office365, ale nie jest potrzebny podczas wywoływania interfejsu Graph API? Mogę autoryzować 'clientId' i' clientSecret' z przepływem przydziału poświadczeń klienta w Graph API, ale nie w Office365. Dlaczego? –

0

Kilka dodatków: Roszczenie odbiorców w asercji jest takie samo, jak punkt końcowy, do którego adresuje żądanie tokena. Jak poprawnie określił Jason, jest to tokenowy punkt końcowy AAD: https://login.windows.net/ {najemca, którego potrzebujesz token aplikacji dla}/oauth2/token. Również nbf i exp są czasem, w którym utworzyłeś asercję w czasie unix epoche, np. w .net zrobiłbyś coś takiego jak "WebConvert.EpocTime (DateTime.UtcNow)". Dla "nie przed" (nbf) może odjąć bufor na skręcenie zegara, np. 5 minut; i dla expires w (exp) dodaj trochę czasu, np. 15 minut (więc twierdzenie pozostaje ważne w tym czasie).

Oto ślad skrzypek z symboliczną życzenie (RAW): POST https://login.windows.net/0e49ef1f-ca07-45f1-b4c0-ac9409d3e576/oauth2/token HTTP/1.1 Content-Type: application/x-www-form-urlencoded klient-request-ID: a8108f88-275b-424d- ac28-f675aabe548e return-client-request-id: true x-client-SKU: .NET x-client-Ver: 2.12.0.0 x-client-CPU: x64 x-client-OS: Microsoft Windows NT 6.2.9200.0 Host: login.windows.net Długość treści: 983 Oczekiwanie: 100-kontynuacja Połączenie: Keep-Alive

zasób = https% 3A% 2F% 2F% 2Fgraph.windows.net & client_id = f17bb8a5-2bef-4ad5-a83f-cd7113449fc2 & client_assertion_type = urna% 3Aietf% 3Aparams% 3Aoauth% 3Aclient-twierdzenie typu% 3Ajwt-okaziciela & client_assertion = eyJhbGciOiJSUzI1NiIsIng1dCI6ImY4S2JVY0xtMnItS2s4b1Z3ZVZYTFU0NzhJcyJ9.eyJhdWQiOiJodHRwczpcL1wvbG9naW4ud2luZG93cy5uZXRcLzBlNDllZjFmLWNhMDctNDVmMS1iNGMwLWFjOTQwOWQzZTU3Nlwvb2F1dGgyXC90b2tlbiIsImV4cCI6MTQyMjk4NDMzNSwiaXNzIjoiZjE3YmI4YTUtMmJlZi00YWQ1LWE4M2YtY2Q3MTEzNDQ5ZmMyIiwianRpIjoiZTI3OTA5YTctZGYwMC00NjBhLTlmZjctOGZkNDExOWVmNTYzIiwibmJmIjoxNDIyOTgzNzM1LCJzdWIiOiJmMTdiYjhhNS0yYmVmLTRhZDUtYTgzZi1jZDcxMTM0NDlmYzIifQ.g9bo4-lxpNJ4kEOMuQxODU-5iakwSVIzyRQEPLdbpuNn_XD4lcvt2yBIWT12EQaUVKkMyqFrDiIh4Oav565-Po7HfhmSPF3URXVj8Kx5lx17Zh0nWiaNkRXEi1vhwswsfjm1o-8B8LGUJTtT6JXTognrueuSL1aEE_-4qSG1y74aoc949Un1pQCjwuBtao4vs4CPJLu9Y9mVbirVRRtiIfxkUMmzf6yfMtuhugoGmrvUYntUo4x 6N2fu4LxGjuIs7czyrMMAmDRo-XK4sAhDo5uof10HKb8ETEU8mhObwNZcz86MYHWbZm3Z_HDOwzC9kA_tp6hWqmlJ3c-gLg5VXA & grant_type = client_credentials

Nadzieja to pomaga! Powodzenia!

Matthias

+1

Uwaga: Możesz sprawdzić, czy twoje potwierdzenie jest poprawne, używając http://jwt.calebb.net i wkleić tam zakodowaną wartość base64url, którą tam wygenerujesz/wyślesz. Powinna to być udana zawartość show, jak w powyższym przykładzie Jasona. –

4

Po prostu udało mi się to sprawić, więc pomyślałem, że wrzucę jeszcze jedną radę do miksu.Wszystkie artykuły instruktażowe mówią, że powinieneś dodać swój certyfikat do pliku manifestu. Miałem problemy z tym, ale tutaj jest to, co zrobiłem, że w końcu to działa:

  • W Azure, przejdź do Ustawienia> Certyfikaty zarządzania
  • Prześlij klucz publiczny jako plik .cer (google wokół jeśli don nie wiem, jak to przekształcić). Powinien to być plik binarny, w którym znajduje się twój edytor tekstu.
  • Po załadowaniu, Microsoft poda ci odcisk kciuka. Znajduje się w kolumnie "Thumbprint". Ale, jest w hex, nie base64. Tak, przekształcić go tak:

    # Hint: use your actual thumbprint, not this fake one 
    echo '5292850026FADB09700E7D6C1BCB1CD1F3270BCC' | xxd -r -p | base64 
    
  • Wreszcie, należy użyć tego base64 zakodowany odcisk palca jako wartość x5t w nagłówku JSON.

+0

Herm, widzę odcisk kciuka, ale kolumna nie jest wystarczająco szeroka, więc skraca ją i dodaje elipsy. Brak oczywistego sposobu na poszerzenie informacji ... Pomysły? – stu

+0

nieważne, mam to ... openssl x509 -in server.cer -fingerprint -noout | tr -d ':' | awk -F "=" '{print 2 $}' xxd -r -p | base64 – stu

Powiązane problemy