Scope parameter support
by Marek Posolda
It seems that for OIDC certification, we will need more proper support
for "scope" parameter. There are few tests from OIDC conformance
testsuite, which end with WARNING because of issues with "scope" parameter.
SUMMARY OF SPECS REQUIREMENTS
-----------------------------
- In OIDC specification, the "scope" parameter is actually REQUIRED. And
you must add the scope value "openid" to all authorization requests.
Hence if you don't use "scope=openid", the request is pure OAuth2
request, but it's not OIDC request.
In https://issues.jboss.org/browse/KEYCLOAK-3147 we discuss the
possibility that we should change our adapters and add "scope=openid" to
all requests, and also the possibility to remove IDToken if it's not
OIDC request (and maybe other things). However it may be potential issue
with backward compatibility with older adapters (which don't add
"scope=openid" at all).
- OIDC also prescribes the "scope=offline_access", which you use if you
want offline token. We actually support this as we have realm role
"offline_access", with scopeParamRequired=true . So this role is applied
just if it's included in scope parameter. This is our only support of
scope param actually. ATM we reference the realm roles by name (role
name must match the value of scope parameter) and clientRoles by
"clientId/roleName" . So it's not very flexible and won't work well in
the future with role namespaces.
- OIDC defines four other scope values, which we don't support, with the
meaning like this:
profile
OPTIONAL. This scope value requests access to the End-User's
default profile Claims, which are: "name", "family_name", "given_name",
"middle_name", "nickname", "preferred_username", "profile", "picture",
"website", "gender", "birthdate", "zoneinfo", "locale", and "updated_at".
email
OPTIONAL. This scope value requests access to the "email" and
"email_verified" Claims.
address
OPTIONAL. This scope value requests access to the "address" Claim.
phone
OPTIONAL. This scope value requests access to the "phone_number"
and "phone_number_verified" Claims.
- Not directly related to scopes, however OIDC also has one parameter
"claims" described in section
http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter .
This allows to define some additional claims, which should be included
in IDToken or UserInfo endpoint in addition to claims specified by
"scope" parameter.
HOW TO IMPLEMENT?
-----------------
My current thinking is, that we will have 2 kinds of protocolMappers and
roles.
1) "Always applied" - Those roles/protocolMappers are always applied to
token even if they are not specified by scope parameter.
2) "Applied on demand" - Those roles/protocolMappers are applied just if
they are specifically requested by scope parameter
For roles, we already have that with "scope param required" flag defined
per roleModel. However for protocolMappers we don't have it yet.
IMO We will also need some more flexible way to specify how the value of
scope parameter will be mapped to roles and protocolMappers. For example
if I use "scope=foo", it can mean that I want realm role "foo1", client
role "client1/foo2" and protocolMapper for "firstName" and "lastName" etc.
I can see 2 possibilities:
a) Configure allowed scope param separately per each role / protocolMapper
If some role has "Scope param required" checked, you will have
possibility to configure list of available values of scope parameter,
which this role will be applied to. This will be configured per-each
role separately.
Example: I have realm role "foo" . I check "scope param required" to
true. Then I will define "scope param values" : "bar" and "baz". It
means that if someone uses parameter "scope=bar" or
scope=baz", then role "foo" will be applied to token. Otherwise it won't
be applied.
Similarly it will be for protocolMappers. We will add switch "Scope
param required" to protocolMappers and we will use list of available
values of scope parameter, which is configured per each protocolMapper
separately.
b) Configure scope parameter in separate place
We will have another tab "Scope parameter config" (or maybe rather
another sub-tab under existing "Scope" tab). Here you will define the
allowed values of scope parameter. For each allowed value, you will
define protocolMappers and roles to apply. Hence for example for
"profile" scope parameter, you will define all protocolMappers for
corresponding claims ( name, family_name, ...) here.
We will still need "scope param required" switch for protocolMappers in
case (b).
My current thinking is to go with (a). So when you go to some role (or
protocolMapper) in admin console you will see if you need scope
parameter and what are available values of scope parameter to request it.
WDYT? Another ideas?
Marek
7 years, 6 months
Docker Protocol?
by Josh Cain
Hi All,
We want to use Keycloak as the IDP/Token issuer for authentication with a
docker registry as per the specification found here:
https://docs.docker.com/registry/spec/auth/
I've implemented a Protocol Mapper in Keycloak that successfully uses the
IDP to perform a login against a registry/docker client. Is this something
that the team is interested in building into the product? If so, I'd be
happy to push back upstream.
Josh Cain | Software Applications Engineer
*Identity and Access Management*
*Red Hat*
+1 843-737-1735
8 years, 1 month
Making ServerInfoAdminResource::ENUMS mutable
by Dmitry Telegin
Hi,
After KEYCLOAK-3618 is (hopefully) resolved, providers will have an
ability to log admin events with custom ResourceType. However, custom
values won't show in the Events - Admin Events - Filter - Resource
Types dropdown (fortunately, the values can still be typed in
directly).
The values in the dropdown reflect
org.keycloak.services.resources.admin.info.ServerInfoAdminResource::ENU
MS content. How about making it mutable, so that providers could
register provider-specific values? These could be some two methods: one
taking (String, String[]) to add values to existing enum maps, another
one taking (Class... enums) to register completely different enums for
provider's private needs.
What do you think?
Dmitry
8 years, 2 months
User SPI cache policies
by Bill Burke
You can now define cache policies per UserStorageProvider.
* NO_CACHE - don't cache users loaded from this provider
* MAX_LIFESPAN - max lifespan of user in cache
* EVICT_DAILY - specify a time of day when the cache will be expired
every day.
* EVICT_WEEKLY - specify a day of the week and time of day when the
cache will be expired.
Bill
8 years, 2 months
Support for key rotation in SAML Redirect binding
by Hynek Mlnarik
Hi All,
re KEYCLOAK-1881 [1]: Key rotation in SAML needs to distill key ID used
for signing for every signature (assertion/document-level) to validate
the signature with the correct key. In POST binding, dsig:KeyInfo
element bears this information in dsig:KeyName both for signed
assertions and for the whole document (a.k.a. protocol message).
For REDIRECT binding in SAML, there is currently no place where KeyID
can be inserted on document level. The document signature in REDIRECT
binding has to be removed from the document (line 578 in [2]) and
replaced by the Signature query parameter, so it is not advisable to put
key ID there.
To solve this, there are multiple options:
1) Modify SAML assertion by adding <Extensions> element that would
include document signing key ID. For consistency reasons, this would
also be present for POST binding SAML documents. This only works for
SAML 2.0 but that does not matter as REDIRECT is new to SAML2.0 anyway.
2) Pass signing key ID in REDIRECT query parameter (next to Signature
and SigAlg parameters) - seems not strictly against the spec but weird
3) Pass signing key ID in custom HTTP header - this might impact
clustering setup and is even weirder than the previous item
4) Claim REDIRECT binding not supporting signatures signed with key
rotation and only support them for POST bindings (for REDIRECT, it would
only work for preset public keys). This is not a viable option for
dynamic key retrieval, so including just for completeness.
Seems like Option 1 or 2 is the one to go. Any thoughts/suggestions?
Thanks
--Hynek
[1] https://issues.jboss.org/browse/KEYCLOAK-1881
[2] https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf
8 years, 2 months
BeerCloak: a comprehensive KeyCloak extension example
by Dmitry Telegin
Hi,
For a while, I've been working on a complex KeyCloak extension (for
those interested - it adds support for hardware OTP generators with
lifecycle management, provisioning etc.)
In the course of my work, I have developed some techniques not
documented elsewhere that I'd like to share. The main focus is creating
custom realm admin resources (even not yet having an official admin
resource SPI). However, this could also serve as a general-purpose
example that combines several SPIs in a form of complete, ready-to-use
extension.
https://github.com/dteleguin/beercloak
As the name suggests, the extension brings into KeyCloak... well, beer
:) you can manage a list of beers, and even try to virtually "drink"
some amount to know how drunk you will be.
Humor aside, what's under the hood:
* a JPA entity (using Entity SPI) and LiquiBase changelog;
* a REST resource (using Realm Resource SPI) with CRUD operations and
one special operation ("drink");
* admin console GUI extensions (using theme mechanism) that work with
REST resource.
Now what makes it "admin resource":
* new roles "view-beer" and "manage-beer" are automatically added to
every existing and newly added realms, as well as included into the
master "admin" role;
* an AdminAuth instance is initialized and subsequently used to secure
REST operations;
* an AdminEventBuilder is initialized to be used for event logging.
Future ideas include adding "Beer" tab for users, where the favorite
beer kind could be chosen; this would be to demonstrate many-to-one and
many-to-one relationships between system entities and custom entities.
This could be later used to create a "secret question"-like
authenticator that would ask a user to enter his/her correct beer
preference.
If there is demand, I think I could turn this example into a complete
tutorial and maybe publish it on GitBooks. Let me know what you think.
Cheers, Dmitry
8 years, 2 months
callback event when realm is cached
by Bill Burke
There is a new callback event
CachedRealmModel.RealmCachedEvent
Whenever a realm is cached, this event is fired off. Each cached
RealmModel instance will can be typecasted to CachedRealmModel which
will allow developers to cache additional things along with the realm.
This will be very useful for providers that want to do some
initialization to speed up processing.
8 years, 2 months
disabling credential types
by Bill Burke
Admin console user credential tab has been changed. It will now list
"disabable credential types". This will be a list of credential types
that can be disabled by the admin (i.e. OTP, PASSWORD, CERT, etc..).
All this hooks into the Credential SPI that I went over a few weeks
ago. So, if new credential types are created, they should show up in
the console too.
Note that disabling happens per credential type, and not per device
(i.e. OTP). I honestly could not figure out how to have an SPI and
generic admin console UI that would take into account ideas like
multiple OTPs, certs, etc...So, disabling is done per type, not per OTP
generator. These are the SPI items that are the backbone of this
feature. They are methods on UserCredentialManager
/** * Calls disableCredential on UserStorageProvider and
UserFederationProviders first, then loop through * each
CredentialProvider. * * @param realm * @param user * @param
credentialType */ void disableCredentialType(RealmModel realm, UserModel user, String credentialType);
/** * Returns a set of credential types that can be disabled by
disableCredentialType() method * * @param realm * @param user * @return */ Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user);
CredentialProviders and UserStorageProviders will be required to
implement these methods if they support credential updates.
8 years, 2 months
Oauth_Token_Request_State change problem
by Maurício Giacomini Penteado
Hello everybody.
In my app when I do login using keycloak javascript lib I receive correctly an Oauth_Token_Request_State but none of my rest service calls are returning their when page is loaded.
Strangely after login if I process a rest service call directly from the browser´s address bar I receive an error (*) reported on server but the Oauth_Token_Request_State is changed by a JSESSIONID and all my rest service calls pass to work without problems.
Is there some way to programmatically change Oauth_Token_Request_State by a JSESSIONID to avoid this situation?
Please, if anyone can help me, I will be very grateful.
Regards,
Maurício.
(*)
08:54:14,544 ERROR [org.jboss.resteasy.resteasy_jaxrs.i18n] (default task-36) RESTEASY002010: Failed to execute: javax.ws.rs.NotFoundException: RESTEASY003210: Could not find resource for full path: http://mydomain.com:8080/services/rs/priv/auth/sayHello
at org.jboss.resteasy.core.registry.SegmentNode.match(SegmentNode.java:114)
at org.jboss.resteasy.core.registry.RootNode.match(RootNode.java:43)
at org.jboss.resteasy.core.registry.RootClassNode.match(RootClassNode.java:48)
at org.jboss.resteasy.core.ResourceMethodRegistry.getResourceInvoker(ResourceMethodRegistry.java:445)
at org.jboss.resteasy.core.SynchronousDispatcher.getInvoker(SynchronousDispatcher.java:257)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:194)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:221)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.keycloak.adapters.undertow.UndertowAuthenticatedActionsHandler.handleRequest(UndertowAuthenticatedActionsHandler.java:66)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.DisableCacheHandler.handleRequest(DisableCacheHandler.java:33)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:51)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:56)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.keycloak.adapters.undertow.ServletPreAuthActionsHandler.handleRequest(ServletPreAuthActionsHandler.java:69)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:284)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:263)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:174)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:793)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
8 years, 2 months