Novinky

Více než 30 IDM realizací v České republice i zahraničí

AMI Praha Přihlašování pomocí OpenID vlastní aplikace
Přihlašování pomocí OpenID vlastní aplikace

Přihlašování pomocí OpenID vlastní aplikace

V AMI Praha jsme se rozhodli využít toho, že všichni naši zaměstnanci mají firemní Google účet a můžeme uplatnit princip OpenID. Google účet tedy použijeme pro přihlášení k jiné aplikaci.

Jako aplikace pro proof of concept přihlašování pomocí OpenID byl vybrán náš Systém evidence práce (SEP).  Cílem bylo umožnit krom stávajícího standardního přihlašování pomocí jména a hesla též přihlášení pomocí OpenID, konkrétně pomocí Google účtu.

Ačkoliv by se mohlo zdát, že tento úkol bude poměrně snadný, protože pro OpenID jistě existují na internetu knihovny a příklady použití, ukázalo se, že obzvlášť zprovoznění možnosti obou způsobů přihlašování do aplikace je složitější než se předpokládalo.

Autentizace pomocí OpenID

Autentizace je proces ověření identity uživatele (na internetu se pro tento proces někdy používají též synonymní výrazy autentikace, autentifikace, nicméně lingvisticky preferovaným ekvivalentem anglického výrazu authentication je právě výraz autentizace.) OpenID je standard umožňující autentizaci k aplikaci pomocí služby třetí strany (Identity Provideru).

Příkladem Identity provideru jsou služby společností Google, Twitter, LinkedIn, Yahoo,  AOL a další.

Aplikace, která využívá pro autentizaci služeb Identity Provideru, se označuje jako relying party (RP).

Aplikace může podporovat použití jednoho i více identity providerů.

Prakticky funguje přihlášení pomocí OpenID následovně:

  • Na login stránce aplikace uživatel zvolí možnost přihlášení pomocí OpenID (např. tlačítkem, případně je zde výběr z identity providerů). Je přesměrován na přihlašovací stránku providera, tedy např. na přihlašovací stránku Google. Po úspěšném přihlášení je přesměrován do aplikace.
  • Pokud je uživatel již v prohlížeči k identity provideru přihlášen, je přesměrován do aplikace rovnou. Při prvním přihlášení bývá ještě nutné udělit aplikaci přístup k údajům od identity providera. Těmito údaji se myslí typicky e-mail nebo jméno uživatele – údaj nutný k identifikaci uživatele, který má být do aplikace přihlášen. Heslo použité k přihlášení k identity provideru se aplikace nedozví.

Použití OpenID pro přihlašování přináší tyto výhody:

  • Aplikace nemusí mít vlastní způsob autentizace.
  • Uživatel se může do více stránek přihlašovat jednotným způsobem bez nutnosti registrace na každou z nich zvlášť (a zapamatování si přihlašovacích údajů).
  • Zrychlení přihlašovacího procesu.
  • Zmenšení bezpečnostních rizik plynoucích z toho, že uživatelé často používají stejný login a heslo do více webových aplikací. Pokud aplikace nemá dobře vyřešenou bezpečnost, může prozrazení hesla v jedné aplikaci vyvolat nutnost změny hesla v dalších aplikacích.

OpenID standard poskytuje framework pro komunikaci mezi identity providerem a relying party. Rozšířením toho je standard OpenID Attribute Exchange, který umožňuje přenos atributů uživatele od identity provideru k relying party.

V souvislosti s OpenID bývá zmiňován též standard OAuth, dnes používán ve verzi 2. OAuth je (na rozdíl od OpenID) místo k autentizaci primárně určen k autorizaci (tedy ověření oprávnění) jedné aplikace získat data jiné aplikace. Například pokud potřebujeme v aplikaci mít možnost načítat události z Google kalendáře uživatele, použijeme OAuth.

Technická realizace OpenID v Java aplikaci

Komunikaci mezi aplikací a identity providerem lze usnadnit použitím již existujících knihoven. Pro Javu konkrétně existuje vícero knihoven, některé z nich již nejsou dále rozvíjené, a pro náš proof of concept jsme zvolili knihovnu OpenId4Java, která se zdála nejvíce použitelná.

Na login stránku bylo přidáno tlačítko obsluhované login servletem. Login servlet zajišťuje komunikaci aplikace s OpenID providerem.

Schéma průběhu této komunikace je následující:

  • Formulář s tlačítkem je odesílaný metodou post.
  • Proces discovery: Pokus získat asociaci pro identifikátor poskytovatele (ověření funkčnosti URI OpenID providera a zahájení komunikace s tímto providerem). Identifikátor poskytovatele OpenID pro Google je to https://www.google.com/accounts/o8/id.
  • Vytvoření žádosti o autentizaci. Do této žádosti jsou přidány též požadavky na získání atributů od OpenId providera. Typicky můžeme požadovat mailovou adresu, jméno, příjmení… Jména atributů jsou zadávána pomocí standardizované URI. Např. pro e-mail má tvar http://axschema.org/contact/email.
  • Žádost je odeslána na OpenID providera.
  • Po proběhnutí přihlášení k provider účtu je zavolána get metoda servletu, ve které dojde k ověření odpovědi. (Ověření ve smyslu toho, že odpověď přišla od správného zdroje).
  • Z odpovědi získáme identifikátor pro usera, který má být přihlášen. Zde je používán e-mail.
  • (Aplikačně specifické) Nezbytné prověření, že uživatel se zadaným emailem v aplikaci existuje a že je platný. Tímto zamezíme přihlašování uživatelů do aplikace jiným mailem než uvedeným v aplikaci (pro restrikci na např. pouze firemní mail) nebo přihlášení již neplatných uživatelů. Pokud uživatel se zadaným mailem nemá mít přístup do aplikace, je navrácen na přihlašovací obrazovku.
  • Pokud uživatel prošel ověřením, je přesměrován na cílovou stránku (tedy do aplikace).

Nutno připomenout, že v rámci komunikace aplikace s OpenID providerem (Googlem) se aplikace nedozví heslo, které uživatel použil pro přihlášení ke Google účtu. Dozví se pouze to, jestli byl uživatel autentizován a hodnoty požadovaných atributů.

Proces discovery, odesílání žádosti a verifikace odpovědi zajištuje knihovna OpenId4Java. Ta také odpovídá za zabezpečení komunikace aplikace s identity providerem. Aby se zabránilo podvržení session, používá se například ověření nonce (number used once). I proto je dobré využít již existující knihovnu a neprogramovat veškerou komunikaci od začátku.

Mohlo by se zdát, že nyní jsme již s řešením přihlášení pomocí OpenID skoro hotovi, ale ještě tomu tak není, zbývá dořešit provedení přihlášení v aplikaci a hlavně, co se ukázalo velkým oříškem, jak zprovoznit obě možnosti přihlašování zároveň.

Přihlášení v aplikaci a kombinace se stávajícím zabezpečením aplikace

Stávající zabezpečení aplikace SEP je řešeno kontejnerem, konkrétně aplikačním serverem Glassfish, pomocí jdbc realmu. V aplikaci je ve web.xml definováno bezpečnostní omezení (security constraint) spočívající v tom, že na dané stránky aplikace (v podstatě vše krom přihlašovací a chybové stránky) se dostane jen uživatel, který má danou roli (SEPAccess). Roli přiděluje uživateli Glassfish po úspěšném přihlášení do aplikace, v definici jdbc realmu je zadáno, která tabulka či view se má používat pro autentizaci, které její sloupce obsahují user name, heslo a group name (neboli přiřazovanou roli). 

Aby uživatel po autentizaci získal přístup do zabezpečené části aplikace, musí získat roli SEPAccess. Tuto roli ale přiděluje pouze Glassfish, nelze ji přidělit z aplikace. Z aplikace lze však vyvolat přihlášení pomocí daného realmu (použitím metody login na třídě com.sun.appserv.security.ProgrammaticLogin). Potřebovali jsme realm, který pouze přiděluje roli SEPAccess a žádná logika autentizace v něm neprobíhá. Proto bylo třeba vytvořit vlastní login modul (OpenIdLoginModule). Tento login modul obsahuje jedinou třídu OpenIdLoginModule, která rozšiřuje com.sun.appserv.security.AppservPasswordLoginModule, a kde je v metodě authenticateUser přiřazena role SEPAccess a tato akce je commitnuta. Třída tedy vypadá takto stručně:

public class OpenIdLoginModule extends AppservPasswordLoginModule{

                @Override

                protected void authenticateUser() throws LoginException {

                   String[] groups = {„SEPAccess“};

                  commitUserAuthentication(groups); 

                }

}

 

Tento login modul je třeba nahrát do pathToGlassfishglassfishdomainsdomain1lib a dále zaregistrovat nový typ realmu použivající tento login modul v login.conf (nachází se v pathToGlassfishglassfishdomainsdomain1config).

Do login.conf stačí přidat:

openIdRealm {

         cz.ami.sep.loginmodule.OpenIdLoginModule required;

};

Pak již lze v Glassfishi definovat openIdRealm sep-openid (klidně stejně jako jdbc realm sep, pro zjednodušení jsme necustomizovali definiční obrazovku openIdRealmu, ale převzali ji od jdbc realmu).

Přihlášení pomocí tohoto realmu je zavoláno z LoginServletu po úspěšné autentizaci uživatele, ale dříve než dojde k přesměrování do aplikace. Tím je zaručeno, že po přesměrování do aplikace se uživatel do aplikace opravdu dostane, protože bude mít přidělenou roli, která k tomu opravňuje.

V Glassfishi jsou tedy definovány 2 realmy, každý z nich se volá z jiného způsobu přihlášení a mohou takto funkčně existovat společně.

Tímto máme funkční přihlašování pomocí OpenID do SEPu zároveň se zachováním možnosti přihlášení pomocí jména a hesla.

 

Autor: Alice Pitková