Chcę stworzyć dość prosty system kontroli dostępu oparty na rolach, korzystając z systemu autoryzacji Keycloak. System zastępowany przez Keycloak pozwala nam stworzyć „użytkownika” będącego członkiem jednej lub kilku „grup”. W tym starszym systemie użytkownik otrzymuje „pozwolenie” na dostęp do każdej z około 250 „możliwości” albo poprzez członkostwo w grupie (gdzie grupom są przypisane uprawnienia), albo przez bezpośrednie przyznanie uprawnień użytkownikowi.
Chciałbym zmapować stary system do autoryzacji Keycloak.
Mapowanie każdej „zdolności” w istniejącym systemie powinno być dla mnie łatwe do zasobu Keycloak i zestawu zakresów Keycloak. Na przykład funkcja „viewAccount” w oczywisty sposób odwzorowuje zasób „konto” i zakres „widoku”; a „viewTransaction” mapuje na zasób „transakcji” ... ale czy najlepiej jest utworzyć tylko jeden zakres „widoku” i używać go w wielu zasobach (konto, transakcja itp.)? A może powinienem utworzyć zakres „viewAccount”, zakres „viewTransaction” itp.?
Podobnie jestem trochę zdezorientowany co do uprawnień. Czy w przypadku każdego praktycznego połączenia zasobów i zakresu zwykle tworzy się pozwolenie? Co robi Keycloak, jeśli istnieje wiele uprawnień pasujących do danego zasobu / zakresu? Domyślam się, że zamiarem Keycloak jest umożliwienie mi skonfigurowania macierzy uprawnień dla zasobów i zakresów, więc na przykład mógłbym mieć uprawnienia dostępu do „kont” i uprawnienia do zakresu „widoku”, więc miałbym uprawnienia przeglądać konta?
Pytam, ponieważ wydaje się, że rezultatem tego wszystkiego jest to, że moja stara funkcja „viewAccount” kończy się utworzeniem zasobu „Account” z zakresem „View” i uprawnieniem „viewAccount”, co wydaje się przenosić mnie z powrotem tam, gdzie byłem. Co jest w porządku, jeśli jest poprawne.
Wreszcie, oczywiście, potrzebuję zestawu zasad, które określają, czy należy zastosować viewAccount. Ale czy mam rację, że to oznacza, że potrzebuję polityki dla każdej starszej grupy, do której mógłby należeć użytkownik? Na przykład, jeśli pełnię rolę „helpdesk”, potrzebuję zasady „członkostwa w helpdesku”, którą mogę następnie dodać do uprawnienia „viewAccount”. Czy to jest poprawne?
Dzięki,
znak
źródło
Odpowiedzi:
Wiem, że spóźniłem się 2+ lata, ale myślę, że podzielę się tym, co wiem i miejmy nadzieję, że złagodzę ból dla przyszłych czytelników. Pełna przejrzystość - w żadnym wypadku nie jestem ekspertem od Keycloak / OAuth / OIDC i wiem, że to głównie z czytania dokumentów, książek, starego dobrego YouTube'a i zabawy z narzędziem.
Ten post będzie składał się z dwóch części:
Keycloak 8.0.0
.Część I.
Kilka terminów, zanim zaczniemy:
Resource-Based
uprawnień stosujesz je bezpośrednio do swojego zasobuScoped-Based
pozwolenie, stosujesz je do zakresu (-ów) lub zakresu (-ów) i zasobu.Zakresy reprezentują zestaw praw do chronionego zasobu. W twoim przypadku masz 2 zasoby:
account
itransaction
dlatego skłaniałbym się do drugiego podejścia.W dłuższej perspektywie, o globalny
view
zakres związaną ze wszystkimi swoimi zasobami (npaccount
,transaction
,customer
,settlement
...) sprawia, że trudno jest autoryzacja zarówno zarządzanie i dostosować się do zmian wymagań bezpieczeństwa.Oto kilka przykładów, które możesz sprawdzić, aby poczuć projekt
Zwróć jednak uwagę - nie twierdzę, że nie należy udostępniać zakresów między zasobami. W rzeczywistości
Keycloak
pozwala na to dla zasobów z tym samymtype
. Możesz na przykład potrzebować obuviewAccount
iviewTransaction
zakresu, aby odczytać transakcję na danym rachunku (w końcu możesz potrzebować dostępu do rachunku, aby wyświetlić transakcje). Twoje wymagania i standardy będą miały duży wpływ na Twój projekt.Przepraszam, nie do końca rozumiem pytanie, więc będę trochę szerszy. Aby przyznać / odmówić dostępu
resource
, musisz:scope
lubresource
(lub obydwoma)aby egzekwowanie zasad zaczęło obowiązywać. Zobacz proces autoryzacji .
To, jak sobie z tym poradzisz, zależy wyłącznie od Ciebie. Możesz na przykład:
Zdefiniuj indywidualne zasady i przypisz je do odpowiednich uprawnień.
Jeszcze lepiej, zdefiniuj indywidualne zasady, a następnie zgrupuj wszystkie powiązane zasady w ramach
aggregated
polityki (polityki zasad), a następnie skojarz tę zagregowaną politykę zscope-based
uprawnieniem. Możesz mieć toscoped-based
uprawnienie dotyczące zarówno zasobu, jak i całego powiązanego z nim zakresu.Możesz też dalej rozdzielić swoje uprawnienia, wykorzystując dwa oddzielne typy. Możesz tworzyć uprawnienia wyłącznie dla swoich zasobów za pomocą
resource-based
typu uprawnienia i oddzielnie kojarzyć inne uprawnienia wyłącznie z zakresem za pomocąscope-based
typu uprawnienia.Masz opcje.
To zależy od
Decision Strategy
Decision Strategy
Logic
Wartość każdej polisy .Logic
Wartość jest podobna Java!
operatora. Może to byćPositive
lubNegative
. GdyLogic
toPositive
, ostateczna ocena polityki pozostaje niezmieniona. Kiedy jejNegative
, ostateczny wynik jest zanegowany (np. Jeśli w ocenie zasady jest fałsz i takLogic
jestNegative
, to tak będzietrue
). Aby uprościć sprawę, załóżmy, że opcjaLogic
jest zawsze ustawiona naPositive
.To
Decision Strategy
jest to, czym naprawdę chcemy się zająć.Decision Strategy
Może być alboUnanimous
alboAffirmative
. Z dokumentów,Skorzystajmy z przykładu, aby lepiej zrozumieć powyższe. Załóżmy, że masz zasób z 2 uprawnieniami i ktoś próbuje uzyskać do niego dostęp (pamiętaj, że
Logic
dotyczyPositive
wszystkich zasad). Teraz:Permission One
maDecision Strategy
zestaw doAffirmative
. Ma również 3 zasady, w których każda z nich ocenia:true
false
false
Ponieważ jedna z zasad jest ustawiona na
true
,Permission One
jest ustawiona natrue
(Twierdząca - tylko 1 musi byćtrue
).Permission Two
maDecision Strategy
zestawUnanimous
z 2 zasadami:true
false
W tym przypadku
Permission Two
jest tak,false
ponieważ jedna zasada jest fałszywa (jednogłośnie - wszystkie muszą byćtrue
).Decision Strategy
jest ustawiony naAffirmative
, dostęp do tego zasobu zostanie przyznany, ponieważPermission One
jesttrue
. Jeśli z drugiej strony serwer zasobówDecision Strategy
jest ustawiony naUnanimous
, dostęp byłby zabroniony.Widzieć:
Będziemy to ponownie odwiedzać. Wyjaśniam, jak ustawić serwer zasobów
Decision Strategy
W części II .Krótka odpowiedź brzmi: tak. Teraz rozwińmy to trochę :)
Jeśli masz następujący scenariusz:
Decision Strategy
ustawiony naUnanimous
lubAffirmative
account/{id}
zasobu totrue
view
zakresu totrue
Otrzymasz dostęp do przeglądania konta.
true
+true
jest równetrue
podAffirmative
lubUnanimous
Decision Strategy
.Teraz, jeśli to masz
Decision Strategy
ustawiony naAffirmative
account/{id}
zasobu totrue
view
zakresu tofalse
Otrzymasz również dostęp do przeglądania konta.
true
+false
jesttrue
w ramachAffirmative
strategii.Chodzi o to, że dostęp do danego zasobu zależy również od twojej konfiguracji, więc bądź ostrożny, ponieważ możesz nie chcieć drugiego scenariusza.
Nie jestem pewien, jak Keycloak zachowywał się 2 lata temu, ale możesz określić zasady oparte na grupach i po prostu dodać wszystkie swoje grupy do tej polityki. Z pewnością nie musisz tworzyć jednej polityki na grupę.
Dość dużo. Można to ustawić na wiele sposobów. Na przykład możesz:
/account/{id}
) I powiąż go zaccount:view
zakresem.helpdesk
rolę w ramach tej politykiScope-Based
uprawnienie o nazwieviewAccount
i powiąż je zscope
,resource
ipolicy
W części II ustawimy coś podobnego.
część druga
Keycloak ma zgrabne małe narzędzie, które pozwala przetestować wszystkie zasady. Co więcej, w rzeczywistości nie trzeba uruchamiać kolejnego serwera aplikacji i wdrażać oddzielnej aplikacji, aby to zadziałało.
Oto scenariusz, który skonfigurujemy:
stackoverflow-demo
bank-api
klienta w tym królestwie/account/{id}
dla tego klientaaccount/{id}
Będzie miałaccount:view
zakresbob
w nowej dziedziniebank_teller
,account_owner
iuser
bob
z żadnymi rolami. Nie jest to teraz potrzebne.Role-Based
zasady:bank_teller
iaccount_owner
mieć dostęp do/account/{id}
zasobuaccount_owner
ma dostęp doaccount:view
zakresuuser
nie ma dostępu do zasobu lub zakresuEvaluate
narzędziem, aby zobaczyć, jak można przyznać lub odmówić dostępu.Wybaczcie, ten przykład jest nierealny, ale nie znam sektora bankowego :)
Konfiguracja Keycloak
Pobierz i uruchom Keycloak
Utwórz początkowego administratora
http://localhost:8080/auth
Administration Console
łączeOdwiedź stronę Pierwsze kroki , aby uzyskać więcej informacji. Do naszych celów wystarczy powyższe.
Przygotowanie sceny
Stwórz nowe królestwo
master
królestwie i kliknijAdd Realm
przycisk.stackoverflow-demo
jako nazwę.Create
.stackoverflow-demo
zamiastmaster
sfery.Zobacz Tworzenie nowego królestwa
Utwórz nowego użytkownika
Users
link po lewej stronieAdd User
przyciskusername
(np.bob
)User Enabled
jest włączonySave
Zobacz Tworzenie nowego użytkownika
Utwórz nowe role
Roles
łączeAdd Role
bank_teller
,account_owner
iuser
Ponownie, nie kojarz swojego użytkownika z rolami. Dla naszych celów nie jest to potrzebne.
Zobacz role
Utwórz klienta
Clients
łączeCreate
bank-api
doClient ID
Root URL
wejściahttp://127.0.0.1:8080/bank-api
Save
Client Protocol
takopenid-connect
Access Type
naconfidential
Authorization Enabled
naOn
Save
. NowyAuthorization
górze powinna pojawić się karta.Authorization
kartę, a następnieSettings
Decision Strategy
jest ustawiony naUnanimous
Decision Strategy
Widzieć:
Utwórz niestandardowe zakresy
Authorization
kartęAuthorization Scopes
>,Create
aby wyświetlićAdd Scope
stronęaccount:view
nazwę i naciśnij Enter.Utwórz „Wyświetl zasoby konta”
Authorization
link powyżejResources
Create
View Account Resource
zarówno, jakName
iDisplay name
account/{id}
doURI
account:view
w poluScopes
tekstowymSave
Zobacz Tworzenie zasobów
Utwórz swoje zasady
Authorization
zakładce kliknijPolicies
Role
zCreate Policy
rozwijanejName
sekcji wpiszOnly Bank Teller and Account Owner Policy
Realm Roles
wybierz zarówno rolę, jakbank_teller
iaccount_owner
Logic
jest ustawiona naPositive
Save
Policies
łączeRole
ponownie z listyCreate Policy
rozwijanej.Only Account Owner Policy
dlaName
Realm Roles
wybierzaccount_owner
Logic
jest ustawiona naPositive
Save
Policies
link u góry, powinieneś zobaczyć nowo utworzone zasady.Zobacz Zasady oparte na rolach
Zwróć uwagę, że Keycloak ma znacznie silniejsze zasady. Zobacz Zarządzanie zasadami
Utwórz uprawnienie oparte na zasobach
Authorization
zakładce kliknijPermissions
Resource-Based
View Account Resource Permission
dlaName
Resources
typemView Account Resource Permission
Apply Policy
wybierzOnly Bank Teller and Account Owner Policy
Decision Strategy
jest ustawiony naUnanimous
Save
Zobacz Tworzenie uprawnień opartych na zasobach
Uff ...
Ocena uprawnienia opartego na zasobach
Authorization
karcie wybierzEvaluate
User
wejściembob
Roles
wybierzuser
Resources
wybierzView Account Resource
i kliknijAdd
View Account Resource with scopes [account:view]
aby zobaczyć wyniki i powinieneś zobaczyćDENY
.Only Bank Teller and Account Owner Policy
. Przetestujmy to, aby upewnić się, że to prawda!Back
link tuż nad wynikiem ocenyaccount_owner
i kliknijEvaluate
. Powinieneś teraz zobaczyć wynik jakoPERMIT
. To samo, jeśli wrócisz i zmienisz rolę nabank_teller
Zobacz Ocenianie i testowanie zasad
Utwórz uprawnienie oparte na zakresie
Permissions
sekcjiScope-Based
ten czas z listyCreate Permission
rozwijanej.Name
, wprowadźView Account Scope Permission
Scopes
, wprowadźaccount:view
Apply Policy
, wprowadźOnly Account Owner Policy
Decision Strategy
jest ustawiony naUnanimous
Save
Zobacz Tworzenie uprawnień opartych na zakresie
Drugi przebieg próbny
Ocena naszych nowych zmian
Authorization
sekcjiEvaluate
bob
bank_teller
View Account Resource
i kliknijAdd
Evaluate
i powinniśmy dostaćDENY
.bank_teller
ma dostęp do,resource
ale niescope
. Tutaj jedno zezwolenie jest oceniane jako prawdziwe, a drugie jako fałszywe. Biorąc pod uwagę, że serwer zasobówDecision Strategy
jest ustawiony naUnanimous
, ostateczną decyzją jestDENY
.Settings
podAuthorization
zakładki i zmienićDecision Strategy
sięAffirmative
i wrócić do kroków 1-6 ponownie. Tym razem ostateczny wynik powinien byćPERMIT
(jedno zezwolenie jest prawdziwe, więc ostateczna decyzja jest prawdziwa).Decision Strategy
powrotem naUnanimous
. Ponownie wróć do kroków od 1 do 6, ale tym razem ustaw rolę jakoaccount_owner
. Tym razem ostateczny wynik jest znowuPERMIT
sensowny, biorąc pod uwagę, żeaccount_owner
ma dostęp zarówno do, jakresource
iscope
.Schludnie :) Mam nadzieję, że to pomoże.
źródło
User Management Access (UMA)
którym właściciel zasobu może udzielić dostępu do chronionego zasobu stronie żądającej (przynajmniej taka jest moja interpretacja).account_owner has access to the account:view scope
. Jak ustabilizujesz związek między tą rolą a zakresem?Chciałem wymusić autoryzację za pomocą czystych metod HTTP, bez użycia adaptera, ponieważ Lua nie miał adaptera. Mam nadzieję, że ta odpowiedź pomoże ludziom szukającym metody innej niż adapter.
Jeśli szukasz adaptera, najlepszym miejscem na rozpoczęcie jest skrócona instrukcja obsługi . Szczególnie przykład autoryzacji rozruchu sprężynowego .
W przypadku implementacji opartej wyłącznie na protokole HTTP:
Krok 1:
Zdefiniuj zasady i uprawnienia w interfejsie administratora Keycloak
Krok 2
Miej wewnętrzne mapowanie, które ścieżki HTTP należą do których zasobów i wymagane zakresy dla każdej ścieżki. Można to również zapisać w pliku konfiguracyjnym . Po wywołaniu określonej trasy wywołaj punkt końcowy tokenu Keycloak, aby sprawdzić poprawność oświadczeń tokenu dostępu.
{ "policy-enforcer": { "user-managed-access" : {}, "enforcement-mode" : "ENFORCING" "paths": [ { "path" : "/someUri/*", "methods" : [ { "method": "GET", "scopes" : ["urn:app.com:scopes:view"] }, { "method": "POST", "scopes" : ["urn:app.com:scopes:create"] } ] } ] } }
Jeśli używasz adaptera i nie określisz ścieżki ani zasobu, adapter wewnętrznie wyszuka ścieżki i zasoby z Keycloak .
Krok 3:
Użyj punktu końcowego tokenu, aby uzyskać lub ocenić uprawnienia. Możesz użyć
response_mode
parametru, aby uzyskać ostateczną decyzję (czy przyznać dostęp) lub pobrać całe uprawnienia.curl -X POST \ http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \ -H "Authorization: Bearer ${access_token}" \ --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \ --data "permission=Resource A#Scope A"
Jeśli żądanie autoryzacji nie jest mapowane na żadne uprawnienie,
403
zamiast tego zwracany jest kod stanu HTTP.źródło