Cyberbezpieczeństwo okiem programisty

OneNote API – uwierzytelnienie i autoryzacja

O

Wprowadzenie

OneNote zapewnia bezpieczny dostęp do swoich notesów za pośrednictwem dwóch usług: konta Microsoft (znanego wcześniej jako Live Connect) oraz Azure Active Directory (AD). Oznacza to, że użytkownik korzystający z zewnętrznej aplikacji, aby otrzymać dostęp do notesów OneNote, musi pomyślnie przejść proces uwierzytelnienia, czy to za pośrednictwem konta MS, czy Azure AD.

Wybór odpowiedniego narzędzia zależy od rodzaju usługi OneNote. W przypadku notesów prywatnych, przechowywanych w usłudze OneDrive, dostęp uzyskuje się za pomocą konta MS. Do notesów biznesowych, dostępnych w usłudze Office365, powinno się korzystać z Azure AD. W obu przypadkach, do przeprowadzenia procesu uwierzytelnienia użytkownika, wykorzystuje się protokół OAuth 2.0.

Niniejszy wpis skupia się na uzyskaniu dostępu do notatników przechowywanych za pomocą usługi OneDrive, więc przedstawiony opis pokazuje, w jaki sposób można uwierzytelnić użytkownika, wykorzystując jego konto Microsoft. Jeśli chodzi o proces uzyskiwania dostępu do notatników Office365, za pomocą Azure AD, to więcej informacji można znaleźć w dokumentacji.

Każde żądanie/zapytanie wysłane do OneNote API musi zawierać prawidłowy token dostępu, przesyłany w nagłówku Authorization. Protokół OAuth 2.0, który jest implementowany przez wspomniane wcześniej usługi, określa sposób uzyskania takiego tokena.

Istotne zagadnienia

Proces uwierzytelnienia i weryfikacji uprawnień, w przypadku konta Microsoft, składa się z kilku istotnych czynników opisanych w bieżącej sekcji. Wszystko sprowadza się to tego, żeby aplikacja (np. webowa), z której korzystają użytkownicy, mogła bezpiecznie integrować się z usługą OneNote i była w stanie uzyskać dostęp do chronionych zasobów, takich jak notatniki OneNote. Najważniejsze zagadnienia zostały opisane poniżej.

Rejestracja aplikacji

Twórca aplikacji, komunikującej się z usługą OneNote, z której będą później korzystać użytkownicy posiadający konto Microsoft, musi w pierwszym kroku zarejestrować swoją aplikację na swoim koncie developerskim. Po zalogowaniu się, developer może utworzyć nową aplikację, klikając na link Utwórz aplikację. Po zdefiniowaniu nazwy oraz języka, aplikacja zostaje utworzona. Na kolejnym ekranie można określić bardziej szczegółowe ustawienia, a także odczytać identyfikator (Client ID) oraz sekretny klucz (Client Secret), czyli dane niezbędne w procesie uzyskiwania tokena dostępu przez użytkowników aplikacji.

Aplikację można zarejestrować jako natywną (urządzenia mobilne i desktopy) lub webową. Omawiany przypadek dotyczy aplikacji webowej, a ustawia się to w drugim kroku, w zakładce Ustawienia interfejsu API. Aby zdefiniować aplikację webową, należy wybrać opcję Nie dla ustawienia Aplikacja kliencka dla urządzeń przenośnych lub komputerów.  W przypadku aplikacji webowej należy również zdefiniować adres zwrotny (redirect URL), przez który serwer implementujący OAuth może komunikować się z aplikacją. Identyfikator oraz klucz można znaleźć po wejściu na zakładkę Ustawienia aplikacji.

Uprawnienia aplikacji

Aplikacja musi posiadać odpowiednie uprawnienia, żeby uzyskać dostęp do notatników OneNote. Te uprawnienia nadaje użytkownik. Najpierw aplikacja prosi o pewien zakres uprawnień, a użytkownik je potwierdza, po poprawnym zalogowaniu się na swoje konto Microsoft. Należy zwrócić uwagę na fakt, że użytkownik może nadać aplikacji tylko takie uprawnienia jakie sam posiada. Oznacza to, że jeśli użytkownik może jedynie przeglądać notatniki, to nie może nadać aplikacji uprawnień do edycji stron. Aplikacja może zażądać następujących zakresów uprawnień:

  • office.onenote_create – możliwość przeglądania notesów użytkownika i tworzenia nowych stron. Brak możliwości przeglądania oraz edycji istniejących stron. Możliwość enumeracji hierarchii notatników i tworzenia stron w dowolnej lokalizacji.
  • office.onenote_update_by_app – możliwość tworzenia, podglądania oraz modyfikacji wszystkich stron stworzonych przez aplikację.
  • office.onenote_update – możliwość tworzenia, podglądania oraz modyfikacji dowolnej zawartości notesów użytkownika.
  • office.onenote – możliwość podglądania notesów oraz stron, ale bez możliwości edycji.
  • wl.signin – pozwala na jednorazowe zalogowanie – użytkownicy, którzy są już zalogowani na koncie Microsoft, są również zalogowani w aplikacji.
  • wl.offline_access – pozwala aplikacji na otrzymanie specjalnego tokena (refresh token), który umożliwia pracę aplikacji, nawet jeśli użytkownik nie jest aktualnie aktywny.

Jedno (lub kilka) z powyższych zakresów podaje się jako parametr zapytania o token dostępu. Więcej informacji o tym, jak powinno wyglądać takie zapytanie, znajduje się w następnym podrozdziale.

Token dostępu

Token dostępu jest najważniejszym elementem całego procesu uwierzytelnienia, ponieważ zapewnia on dostęp aplikacji webowej do notatników OneNote, poprzez określone wywołania API. Token dostępu umieszcza się w nagłówku Authorization zapytań HTTP i dzięki temu usługa OneNote API jest w stanie zweryfikować, czy powinna obsłużyć takie zapytanie, lub inaczej mówiąc, czy użytkownik, który je wywołał, ma dostęp do chronionych zasobów.

Kiedy użytkownik zaczyna korzystać z aplikacji webowej, zanim otrzyma dostęp do notatników, musi potwierdzić swoją tożsamość. Aplikacja współpracująca z protokołem OAuth 2, powinna go skierować na stronę logowania do konta Microsoft. Po wpisaniu prawidłowych danych uwierzytelniających, użytkownik zostaje poproszony o potwierdzenie nadania uprawnień aplikacji, z której obecnie korzysta. Po tym zabiegu użytkownik otrzymuje token dostępu, który uprawnia go, za pośrednictwem aplikacji, do korzystania z usługi OneNote API. Zakres tejże usługi zależy od wspomnianych wcześniej uprawnień.

Wykorzystywany tutaj standard OAuth 2 definiuje dwie drogi do uzyskania tokena dostępu:

  • Token Flow – znany również jako Implicit Flow. Polega na uzyskaniu tokena dostępu w jednym zapytaniu. Użyteczny w przypadku chęci uzyskania szybkiego dostępu do chronionych zasobów. Ważność tokena szybko ulega przedawnieniu, więc nie pozwala na długoterminowe połączenia.
  • Code Flow – znany pod nazwą Authentication Code Flow. Proces przebiegający w dwóch krokach. Pobranie kodu autoryzacji w pierwszym wywołaniu i wymiana na token dostępu w drugim wywołaniu. Razem z użyciem zakresu dostępu wl.offline_access, aplikacja może otrzymać token pozwalający na długoterminowy dostęp (tzw. refresh token).

Token Flow

Polega na uzyskaniu tokena dostępu zaraz po prawidłowym zalogowaniu się użytkownika oraz potwierdzeniu uprawnień. Ekran logowania pojawia się po wywołaniu poniższego zapytania HTTP w przeglądarce (lub kontrolce przeglądarki, jeśli nie jest to aplikacja webowa):

https://login.live.com/oauth20_authorize.srf
?response_type=token
&client_id={client_id}
&redirect_uri={redirect_uri}
&scope={scope}

gdzie:

  • response_type – Typ używanego podejścia (drogi uzyskania tokena dostępu). W tym przypadku jest to token.
  • client_id – Identyfikator klienta otrzymany po zarejestrowaniu aplikacji.
  • redirect_uri – URL zwrotny przypisany zarejestrowanej aplikacji. Z użyciem tego adresu zostanie zwrócony token dostępu. Aplikacje mobilne oraz desktopowe mogą użyć adresu https://login.live.com/oauth20_desktop.srf. Jeśli jest to aplikacja webowa, to redirect_uri musi być wcześniej zarejestrowany.
  • scope – zakres dostępu wymagany przez aplikację. Przykładowa wartość office.onenote%20wl.signin oznacza, że aplikacja prosi o możliwość podglądania notesów (office.onenote) oraz możliwość jednorazowego logowania (wl.signin).

Po prawidłowej weryfikacji, przeglądarka przekierowuje użytkownika do podanego adresu URL oraz dokleja parametry dostępu (m.in. token). Otrzymany token jest ważny przez ilość sekund określoną w parametrze expires_in:

https://your-redirect-url
#access_token=EwB4Aq...%3d
&token_type=bearer
&expires_in=3600
&scope=office.onenote%20wl.signin
&user_id=c519ea026ece84de362cfa77dc0f2348

Należy zwrócić tutaj uwagę na fakt, że doklejone parametry zaczynają się od znaku #, który oznacza kotwicę (ang. anchor), czyli link przenoszący do miejsca na bieżącej stronie. Problemem jest to, że tej części URL-a (po znaku #) nie można odczytać po stronie serwera, ponieważ przeglądarka nawet nie wysyła tego fragmentu do serwera. Oznacza to, że otrzymane parametry można odczytać po stronie klienta (z użyciem np. JavaScript). W przypadku aplikacji webowych, w których zwrócone dane będą parsowane po stronie serwerowej, lepiej jest skorzystać z drugiego podejścia.

Code Flow

To podejście, w przeciwieństwie do Token Flow, składa się z dwóch kroków, ale daje też więcej możliwości. Pierwszy krok również polega na przekierowaniu użytkownika na stronę logowania do jego konta, potwierdzeniu uprawnień oraz przekierowaniu na podany adres zwrotny. Różnicą jest to, że zamiast tokena dostępu, zwracany jest najpierw kod autoryzacji (ang. Authorization Code). Dopiero ten kod posłuży do uzyskania tokena dostępu.

Zapytanie HTTP kierujące do strony logowania wygląda podobnie jak w poprzednim podejściu, z wyjątkiem parametru response_type:

https://login.live.com/oauth20_authorize.srf
?response_type=code
&client_id={client-id}
&redirect_uri={redirect-uri}
&scope={scope}

Po prawidłowej weryfikacji, przeglądarka przekierowuje użytkownika do podanego adresu URL oraz dokleja tylko jeden parametr z przypisaną wartością – kod autoryzacji:

https://your-redirect-uri
?code=M57010781-9e8c-e31e-ca0d-46bc104236c4

Otrzymany kod jest ważny tylko przez kilka minut, więc należy go jak najszybciej wymienić na token dostępu. Można tego dokonać poprzez wywołania zapytania HTTP POST:

POST https://login.live.com/oauth20_token.srf
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&client_id={client_id}
&client_secret={client_secret}
&code={code}
&redirect_uri={redirect_uri}

gdzie jako client_secret podaje się tajny klucz klienta, przypisany do aplikacji po zarejestrowaniu, a w parametrze code przekazuje się wspomniany przed chwilą kod autoryzacji. W przypadku powodzenia, zwracane są dane w postaci JSON, które zawierają access_token oraz, jeśli wcześniej dołączono do zapytania zakres wl.offline_access, tak zwany token odświeżający (parametr refresh_token). Token dostępu jest ważny przez ilość sekund określoną w parametrze expires_in. Przykładowa odpowiedź:

{
"token_type":"bearer",
"expires_in":3600,
"scope":"office.onenote wl.sign-in wl.offline-access",
"access_token":"EwCAAq...wE=",
"refresh_token":"MCvePE...$",
"user_id":"c519ea026ece84de362cfa77dc0f2348"
}

Więcej informacji traktujących o refresh token można znaleźć w dalszej części artykułu. Najważniejszy jest na razie otrzymany token dostępu, który umożliwia wykonywania autoryzowanych zapytań do OneNote API.

Zapytania OneNote API

Po otrzymaniu tokena dostępu, należy go dołączać w nagłówku Authorization, do każdego wywołania OneNote API. Przykładowe zapytanie, które zwróci 5 notesów użytkownika, powinno wyglądać następująco:

GET https://www.onenote.com/api/v1.0/me/notes/notebooks?top=5
Authorization: Bearer {access-token}

Należy pamiętać, że token dostępu jest ważny tylko przez godzinę. Po tym czasie należy poprosić o nowy token. Jeśli użytkownik pozostaje zalogowany na swoim koncie Microsoft, przy następnej prośbie o token, nie będzie musiał potwierdzać nadania uprawnień (chyba, że wcześniej sam cofnął uprawnienia dla aplikacji).

Odświeżanie tokena dostępu

Kiedy token dostępu traci ważność, zapytania OneNote API zwracają w odpowiedzi kod 401 Unauthorized. W takim przypadku istnieją dwie możliwości uzyskania nowego tokena dostępu:

  • Powtórzenie procesu autoryzacji poprzez przekierowanie użytkownika na stronę logowania do konta Microsoft (https://login.live.com/oauth20_authorize.srf). Jeśli użytkownik nie wylogował się wcześniej ze swojego konta Microsoft, ani nie cofnął nadanych wcześniej uprawnień aplikacji, operacja powinna przebiec transparentnie, tzn. użytkownik powinien otrzymać nowy token dostępu bez ponownego wpisywania danych dostępu, czy potwierdzania nadania uprawnień. Takie podejście sprawdza się znakomicie w przypadku aplikacji webowych, gdzie nieodłącznym elementem jest interakcja z użytkownikiem.
  • Użycie specjalnego tokena odświeżającego (refresh token), o którym więcej informacji można znaleźć poniżej. To podejście jest niezbędne, jeśli aplikacja powinna działać samodzielnie, bez zalogowanego użytkownika.

W celu uzyskania tokena refresh, należy skorzystać z podejścia Code Flow, opisywanego w sekcji Token Dostępu bieżącego artykułu. Podczas wykonywania pierwszego zapytania, o kod autoryzacji, należy przekazać wartość wl.offline_access w parametrze scope:

https://login.live.com/oauth20_authorize.srf
?response_type=code
&client_id={client-id}
&redirect_uri={redirect-uri}
&scope=wl.offline_access%20office.onenote

Po wykonaniu drugiego zapytania:

POST https://login.live.com/oauth20_token.srf
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&client_id={client_id}
&client_secret={client_secret}
&code={code}
&redirect_uri={redirect_uri}

Powinien zostać zwrócony token dostępu wraz z tokenem odświeżającym (refresh token):

{
"token_type":"bearer",
"expires_in": 3600,
"scope":"office.onenote wl.offline-access",
"access_token":"EwB4Aq...wE=",
"refresh_token":"MCVw8k...$",
"user_id":"c519ea026ece84de362cfa77dc0f2348"
}

Mając refresh token, po wygaśnięciu ważności tokena dostępu, można bez problemu poprosić o nowy token dostępu, wywołując poniższe zapytanie:

POST https://login.live.com/oauth20_token.srf
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&client_id={client-id}
&client_secret={client-secret}
&redirect_uri={redirect-uri}
&refresh_token={refresh-token}

Odpowiedź wygląda analogicznie do tej, przedstawionej powyżej. Zapytanie różni się tym, że zamiast kodu autoryzacji, przekazany jest refresh token (grant_type=refresh_token).

Wylogowanie

W celu wylogowania użytkownika z jego konta Microsoft, a tym samym odłączenie go od usługi OneNote API, należy wywołać poniższe zapytanie HTTP:

https://login.live.com/oauth20_logout.srf
?client_id={client_id}
&redirect_uri={redirect_uri}

Obsługa błędów

Kiedy podczas procesu uwierzytelniania występuje błąd, przeglądarka zostaje przekierowana na stronę z komunikatem błędu. Strona zawiera treść zrozumiałą dla użytkownika, ale URL do tej strony zawiera dodatkowe informacje, które mogą pomóc w zidentyfikowaniu przyczyny błędu. Parametr błędu jest dołączany jako kotwica (anchor):

#error={error_code}&error_description={message}

Jeśli użytkownik zdecyduje się nie przyznawać uprawnień aplikacji, zostanie przekierowany na podaną wcześniej stronę (redirect_uri) wraz z dołączonym komunikatem błędu.

Podsumowanie

Niniejszy wpis jest czysto teoretyczny i opisuje proces uwierzytelnienia oraz autoryzacji, wykorzystując protokół OAuth 2.0, na przykładzie usługi OneNote API. Więcej informacji na ten temat można znaleźć w dokumentacji MSDN (OneNote authentication and permissions), która została wykorzystana do napisania tego artykułu.

Następny wpis będzie zawierał krótki opis prostej aplikacji webowej integrującej się z OneNote API za pomocą protokołu OAuth 2.0.

O autorze

Łukasz Mieczkowski

Programista, który zainteresował się cyberbezpieczeństwem.

Dodaj komentarz

Cyberbezpieczeństwo okiem programisty

Łukasz Mieczkowski

Programista, który zainteresował się cyberbezpieczeństwem.

Kontakt

Zapraszam do kontaktu za pośrednictwem mediów społecznościowych.