protected void addComposites(AccessToken token, RoleModel role) { AccessToken.Access access = null; if (role.getContainer() instanceof RealmModel) { access = token.getRealmAccess(); if (token.getRealmAccess() == null) { access = new AccessToken.Access(); token.setRealmAccess(access); } else if (token.getRealmAccess().getRoles() != null && token.getRealmAccess().isUserInRole(role.getName())) return; } else { ClientModel app = (ClientModel) role.getContainer(); access = token.getResourceAccess(app.getClientId()); if (access == null) { access = token.addAccess(app.getClientId()); if (app.isSurrogateAuthRequired()) access.verifyCaller(true); } else if (access.isUserInRole(role.getName())) return; } access.addRole(role.getName()); if (!role.isComposite()) return; for (RoleModel composite : role.getComposites()) { addComposites(token, composite); } }
protected AccessToken initToken( RealmModel realm, ClientModel client, UserModel user, UserSessionModel session, ClientSessionModel clientSession) { AccessToken token = new AccessToken(); if (clientSession != null) token.clientSession(clientSession.getId()); token.id(KeycloakModelUtils.generateId()); token.subject(user.getId()); token.audience(client.getClientId()); token.issuedNow(); token.issuedFor(client.getClientId()); token.issuer(clientSession.getNote(OIDCLoginProtocol.ISSUER)); if (session != null) { token.setSessionState(session.getId()); } if (realm.getAccessTokenLifespan() > 0) { token.expiration(Time.currentTime() + realm.getAccessTokenLifespan()); } Set<String> allowedOrigins = client.getWebOrigins(); if (allowedOrigins != null) { token.setAllowedOrigins(allowedOrigins); } return token; }
private ClientSessionCode parseClientSessionCode(String code) { ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realm); if (clientCode != null && clientCode.isValid(AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) { ClientSessionModel clientSession = clientCode.getClientSession(); if (clientSession != null) { ClientModel client = clientSession.getClient(); if (client == null) { throw new IdentityBrokerException("Invalid client"); } logger.debugf("Got authorization code from client [%s].", client.getClientId()); } logger.debugf("Authorization code is valid."); return clientCode; } throw new IdentityBrokerException( "Invalid code, please login again through your application."); }
@Override public void backchannelLogout(UserSessionModel userSession, ClientSessionModel clientSession) { ClientModel client = clientSession.getClient(); SamlClient samlClient = new SamlClient(client); String logoutUrl = getLogoutServiceUrl(uriInfo, client, SAML_POST_BINDING); if (logoutUrl == null) { logger.warnv( "Can't do backchannel logout. No SingleLogoutService POST Binding registered for client: {1}", client.getClientId()); return; } SAML2LogoutRequestBuilder logoutBuilder = createLogoutRequest(logoutUrl, clientSession, client); String logoutRequestString = null; try { JaxrsSAML2BindingBuilder binding = createBindingBuilder(samlClient); logoutRequestString = binding.postBinding(logoutBuilder.buildDocument()).encoded(); } catch (Exception e) { logger.warn("failed to send saml logout", e); return; } HttpClient httpClient = session.getProvider(HttpClientProvider.class).getHttpClient(); for (int i = 0; i < 2; i++) { // follow redirects once try { List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add( new BasicNameValuePair(GeneralConstants.SAML_REQUEST_KEY, logoutRequestString)); formparams.add( new BasicNameValuePair("BACK_CHANNEL_LOGOUT", "BACK_CHANNEL_LOGOUT")); // for Picketlink // todo remove // this UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8"); HttpPost post = new HttpPost(logoutUrl); post.setEntity(form); HttpResponse response = httpClient.execute(post); try { int status = response.getStatusLine().getStatusCode(); if (status == 302 && !logoutUrl.endsWith("/")) { String redirect = response.getFirstHeader(HttpHeaders.LOCATION).getValue(); String withSlash = logoutUrl + "/"; if (withSlash.equals(redirect)) { logoutUrl = withSlash; continue; } } } finally { HttpEntity entity = response.getEntity(); if (entity != null) { InputStream is = entity.getContent(); if (is != null) is.close(); } } } catch (IOException e) { logger.warn("failed to send saml logout", e); } break; } }
private void processRoles( Set<RoleModel> inputRoles, List<RoleModel> realmRoles, MultivaluedHashMap<String, ClientRoleEntry> clientRoles) { for (RoleModel role : inputRoles) { if (role.getContainer() instanceof RealmModel) { realmRoles.add(role); } else { ClientModel currentClient = (ClientModel) role.getContainer(); ClientRoleEntry clientRole = new ClientRoleEntry( currentClient.getClientId(), currentClient.getName(), role.getName(), role.getDescription()); clientRoles.add(currentClient.getClientId(), clientRole); } } }
/** * Get consents granted by the user * * @param id User id * @return */ @Path("{id}/consents") @GET @NoCache @Produces(MediaType.APPLICATION_JSON) public List<Map<String, Object>> getConsents(final @PathParam("id") String id) { auth.requireView(); UserModel user = session.users().getUserById(id, realm); if (user == null) { throw new NotFoundException("User not found"); } List<Map<String, Object>> result = new LinkedList<>(); Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user); for (ClientModel client : realm.getClients()) { UserConsentModel consent = user.getConsentByClient(client.getId()); boolean hasOfflineToken = offlineClients.contains(client); if (consent == null && !hasOfflineToken) { continue; } UserConsentRepresentation rep = (consent == null) ? null : ModelToRepresentation.toRepresentation(consent); Map<String, Object> currentRep = new HashMap<>(); currentRep.put("clientId", client.getClientId()); currentRep.put( "grantedProtocolMappers", (rep == null ? Collections.emptyMap() : rep.getGrantedProtocolMappers())); currentRep.put( "grantedRealmRoles", (rep == null ? Collections.emptyList() : rep.getGrantedRealmRoles())); currentRep.put( "grantedClientRoles", (rep == null ? Collections.emptyMap() : rep.getGrantedClientRoles())); List<Map<String, String>> additionalGrants = new LinkedList<>(); if (hasOfflineToken) { Map<String, String> offlineTokens = new HashMap<>(); offlineTokens.put("client", client.getId()); // TODO: translate offlineTokens.put("key", "Offline Token"); additionalGrants.add(offlineTokens); } currentRep.put("additionalGrants", additionalGrants); result.add(currentRep); } return result; }
public String toJBossSubsystemConfig( RealmModel realmModel, ClientModel clientModel, URI baseUri) { StringBuffer buffer = new StringBuffer(); buffer.append("<secure-deployment name=\"WAR MODULE NAME.war\">\n"); buffer.append(" <realm>").append(realmModel.getName()).append("</realm>\n"); buffer .append(" <auth-server-url>") .append(baseUri.toString()) .append("</auth-server-url>\n"); if (clientModel.isBearerOnly()) { buffer.append(" <bearer-only>true</bearer-only>\n"); } else if (clientModel.isPublicClient()) { buffer.append(" <public-client>true</public-client>\n"); } buffer .append(" <ssl-required>") .append(realmModel.getSslRequired().name()) .append("</ssl-required>\n"); buffer.append(" <resource>").append(clientModel.getClientId()).append("</resource>\n"); String cred = clientModel.getSecret(); if (showClientCredentialsAdapterConfig(clientModel)) { Map<String, Object> adapterConfig = getClientCredentialsAdapterConfig(clientModel); for (Map.Entry<String, Object> entry : adapterConfig.entrySet()) { buffer.append(" <credential name=\"" + entry.getKey() + "\">"); Object value = entry.getValue(); if (value instanceof Map) { buffer.append("\n"); Map<String, Object> asMap = (Map<String, Object>) value; for (Map.Entry<String, Object> credEntry : asMap.entrySet()) { buffer.append( " <" + credEntry.getKey() + ">" + credEntry.getValue().toString() + "</" + credEntry.getKey() + ">\n"); } buffer.append(" </credential>\n"); } else { buffer.append(value.toString()).append("</credential>\n"); } } } if (clientModel.getRoles().size() > 0) { buffer.append(" <use-resource-role-mappings>true</use-resource-role-mappings>\n"); } buffer.append("</secure-deployment>\n"); return buffer.toString(); }
/** * Get client session stats * * <p>Returns a JSON map. The key is the client id, the value is the number of sessions that * currently are active with that client. Only clients that actually have a session associated * with them will be in this map. * * @return */ @Path("client-session-stats") @GET @NoCache @Produces(MediaType.APPLICATION_JSON) public List<Map<String, String>> getClientSessionStats() { auth.requireView(); List<Map<String, String>> data = new LinkedList<Map<String, String>>(); for (ClientModel client : realm.getClients()) { int size = session.sessions().getActiveUserSessions(client.getRealm(), client); if (size == 0) continue; Map<String, String> map = new HashMap<String, String>(); map.put("id", client.getId()); map.put("clientId", client.getClientId()); map.put("active", size + ""); data.add(map); } return data; }
@Path("revoke-grant") @POST public Response processRevokeGrant(final MultivaluedMap<String, String> formData) { if (auth == null) { return login("applications"); } require(AccountRoles.MANAGE_ACCOUNT); csrfCheck(formData); String clientId = formData.getFirst("clientId"); if (clientId == null) { return account.setError(Messages.CLIENT_NOT_FOUND).createResponse(AccountPages.APPLICATIONS); } ClientModel client = realm.getClientById(clientId); if (client == null) { return account.setError(Messages.CLIENT_NOT_FOUND).createResponse(AccountPages.APPLICATIONS); } // Revoke grant in UserModel UserModel user = auth.getUser(); user.revokeConsentForClient(client.getId()); OfflineTokenUtils.revokeOfflineToken(session, realm, user, client); // Logout clientSessions for this user and client AuthenticationManager.backchannelUserFromClient(session, realm, user, client, uriInfo, headers); event .event(EventType.REVOKE_GRANT) .client(auth.getClient()) .user(auth.getUser()) .detail(Details.REVOKED_CLIENT, client.getClientId()) .success(); setReferrerOnPage(); UriBuilder builder = Urls.accountBase(uriInfo.getBaseUri()).path(AccountService.class, "applicationsPage"); String referrer = uriInfo.getQueryParameters().getFirst("referrer"); if (referrer != null) { builder.queryParam("referrer", referrer); } URI location = builder.build(realm.getName()); return Response.seeOther(location).build(); }
public AccessTokenResponseBuilder generateIDToken() { if (accessToken == null) { throw new IllegalStateException("accessToken not set"); } idToken = new IDToken(); idToken.id(KeycloakModelUtils.generateId()); idToken.subject(accessToken.getSubject()); idToken.audience(client.getClientId()); idToken.issuedNow(); idToken.issuedFor(accessToken.getIssuedFor()); idToken.issuer(accessToken.getIssuer()); idToken.setSessionState(accessToken.getSessionState()); if (realm.getAccessTokenLifespan() > 0) { idToken.expiration(Time.currentTime() + realm.getAccessTokenLifespan()); } transformIDToken( session, idToken, realm, client, userSession.getUser(), userSession, clientSession); return this; }
public InstallationAdapterConfig toInstallationRepresentation( RealmModel realmModel, ClientModel clientModel, URI baseUri) { InstallationAdapterConfig rep = new InstallationAdapterConfig(); rep.setAuthServerUrl(baseUri.toString()); rep.setRealm(realmModel.getName()); rep.setSslRequired(realmModel.getSslRequired().name().toLowerCase()); if (clientModel.isPublicClient() && !clientModel.isBearerOnly()) rep.setPublicClient(true); if (clientModel.isBearerOnly()) rep.setBearerOnly(true); if (clientModel.getRoles().size() > 0) rep.setUseResourceRoleMappings(true); rep.setResource(clientModel.getClientId()); if (showClientCredentialsAdapterConfig(clientModel)) { Map<String, Object> adapterConfig = getClientCredentialsAdapterConfig(clientModel); rep.setCredentials(adapterConfig); } return rep; }
public void updateClientFromRep( ClientRepresentation rep, ClientModel client, KeycloakSession session) throws ModelDuplicateException { if (TRUE.equals(rep.isServiceAccountsEnabled()) && !client.isServiceAccountsEnabled()) { new ClientManager(new RealmManager(session)).enableServiceAccount(client); } if (!rep.getClientId().equals(client.getClientId())) { new ClientManager(new RealmManager(session)).clientIdChanged(client, rep.getClientId()); } RepresentationToModel.updateClient(rep, client); if (Profile.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) { if (TRUE.equals(rep.getAuthorizationServicesEnabled())) { authorization().enable(); } else { authorization().disable(); } } }
/** * Get a user dedicated to the service account * * @return */ @Path("service-account-user") @GET @NoCache @Produces(MediaType.APPLICATION_JSON) public UserRepresentation getServiceAccountUser() { auth.requireView(); if (client == null) { throw new NotFoundException("Could not find client"); } UserModel user = session.users().getServiceAccount(client); if (user == null) { if (client.isServiceAccountsEnabled()) { new ClientManager(new RealmManager(session)).enableServiceAccount(client); user = session.users().getServiceAccount(client); } else { throw new BadRequestException( "Service account not enabled for the client '" + client.getClientId() + "'"); } } return ModelToRepresentation.toRepresentation(session, realm, user); }
public void enableServiceAccount(ClientModel client) { client.setServiceAccountsEnabled(true); // Add dedicated user for this service account if (realmManager.getSession().users().getServiceAccount(client) == null) { String username = ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + client.getClientId(); logger.debugf("Creating service account user '%s'", username); // Don't use federation for service account user UserModel user = realmManager.getSession().userStorage().addUser(client.getRealm(), username); user.setEnabled(true); user.setEmail(username + "@placeholder.org"); user.setServiceAccountClientLink(client.getId()); } // Add protocol mappers to retrieve clientId in access token if (client.getProtocolMapperByName( OIDCLoginProtocol.LOGIN_PROTOCOL, ServiceAccountConstants.CLIENT_ID_PROTOCOL_MAPPER) == null) { logger.debugf( "Creating service account protocol mapper '%s' for client '%s'", ServiceAccountConstants.CLIENT_ID_PROTOCOL_MAPPER, client.getClientId()); ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper( ServiceAccountConstants.CLIENT_ID_PROTOCOL_MAPPER, ServiceAccountConstants.CLIENT_ID, ServiceAccountConstants.CLIENT_ID, "String", false, "", true, true); client.addProtocolMapper(protocolMapper); } // Add protocol mappers to retrieve hostname and IP address of client in access token if (client.getProtocolMapperByName( OIDCLoginProtocol.LOGIN_PROTOCOL, ServiceAccountConstants.CLIENT_HOST_PROTOCOL_MAPPER) == null) { logger.debugf( "Creating service account protocol mapper '%s' for client '%s'", ServiceAccountConstants.CLIENT_HOST_PROTOCOL_MAPPER, client.getClientId()); ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper( ServiceAccountConstants.CLIENT_HOST_PROTOCOL_MAPPER, ServiceAccountConstants.CLIENT_HOST, ServiceAccountConstants.CLIENT_HOST, "String", false, "", true, true); client.addProtocolMapper(protocolMapper); } if (client.getProtocolMapperByName( OIDCLoginProtocol.LOGIN_PROTOCOL, ServiceAccountConstants.CLIENT_ADDRESS_PROTOCOL_MAPPER) == null) { logger.debugf( "Creating service account protocol mapper '%s' for client '%s'", ServiceAccountConstants.CLIENT_ADDRESS_PROTOCOL_MAPPER, client.getClientId()); ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper( ServiceAccountConstants.CLIENT_ADDRESS_PROTOCOL_MAPPER, ServiceAccountConstants.CLIENT_ADDRESS, ServiceAccountConstants.CLIENT_ADDRESS, "String", false, "", true, true); client.addProtocolMapper(protocolMapper); } }
protected Response logoutRequest( LogoutRequestType logoutRequest, ClientModel client, String relayState) { SamlClient samlClient = new SamlClient(client); // validate destination if (logoutRequest.getDestination() != null && !uriInfo.getAbsolutePath().equals(logoutRequest.getDestination())) { event.detail(Details.REASON, "invalid_destination"); event.error(Errors.INVALID_SAML_LOGOUT_REQUEST); return ErrorPage.error(session, Messages.INVALID_REQUEST); } // authenticate identity cookie, but ignore an access token timeout as we're logging out // anyways. AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, false); if (authResult != null) { String logoutBinding = getBindingType(); if ("true".equals(samlClient.forcePostBinding())) logoutBinding = SamlProtocol.SAML_POST_BINDING; String bindingUri = SamlProtocol.getLogoutServiceUrl(uriInfo, client, logoutBinding); UserSessionModel userSession = authResult.getSession(); userSession.setNote(SamlProtocol.SAML_LOGOUT_BINDING_URI, bindingUri); if (samlClient.requiresRealmSignature()) { userSession.setNote( SamlProtocol.SAML_LOGOUT_SIGNATURE_ALGORITHM, samlClient.getSignatureAlgorithm().toString()); } if (relayState != null) userSession.setNote(SamlProtocol.SAML_LOGOUT_RELAY_STATE, relayState); userSession.setNote(SamlProtocol.SAML_LOGOUT_REQUEST_ID, logoutRequest.getID()); userSession.setNote(SamlProtocol.SAML_LOGOUT_BINDING, logoutBinding); userSession.setNote( SamlProtocol.SAML_LOGOUT_CANONICALIZATION, samlClient.getCanonicalizationMethod()); userSession.setNote( AuthenticationManager.KEYCLOAK_LOGOUT_PROTOCOL, SamlProtocol.LOGIN_PROTOCOL); // remove client from logout requests for (ClientSessionModel clientSession : userSession.getClientSessions()) { if (clientSession.getClient().getId().equals(client.getId())) { clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name()); } } logger.debug("browser Logout"); return authManager.browserLogout( session, realm, userSession, uriInfo, clientConnection, headers); } else if (logoutRequest.getSessionIndex() != null) { for (String sessionIndex : logoutRequest.getSessionIndex()) { ClientSessionModel clientSession = session.sessions().getClientSession(realm, sessionIndex); if (clientSession == null) continue; UserSessionModel userSession = clientSession.getUserSession(); if (clientSession.getClient().getClientId().equals(client.getClientId())) { // remove requesting client from logout clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name()); // Remove also other clientSessions of this client as there could be more in this // UserSession if (userSession != null) { for (ClientSessionModel clientSession2 : userSession.getClientSessions()) { if (clientSession2.getClient().getId().equals(client.getId())) { clientSession2.setAction(ClientSessionModel.Action.LOGGED_OUT.name()); } } } } try { authManager.backchannelLogout( session, realm, userSession, uriInfo, clientConnection, headers, true); } catch (Exception e) { logger.warn("Failure with backchannel logout", e); } } } // default String logoutBinding = getBindingType(); String logoutBindingUri = SamlProtocol.getLogoutServiceUrl(uriInfo, client, logoutBinding); String logoutRelayState = relayState; SAML2LogoutResponseBuilder builder = new SAML2LogoutResponseBuilder(); builder.logoutRequestID(logoutRequest.getID()); builder.destination(logoutBindingUri); builder.issuer(RealmsResource.realmBaseUrl(uriInfo).build(realm.getName()).toString()); JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder().relayState(logoutRelayState); if (samlClient.requiresRealmSignature()) { SignatureAlgorithm algorithm = samlClient.getSignatureAlgorithm(); KeyManager.ActiveKey keys = session.keys().getActiveKey(realm); binding .signatureAlgorithm(algorithm) .signWith(keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()) .signDocument(); } try { if (SamlProtocol.SAML_POST_BINDING.equals(logoutBinding)) { return binding.postBinding(builder.buildDocument()).response(logoutBindingUri); } else { return binding.redirectBinding(builder.buildDocument()).response(logoutBindingUri); } } catch (Exception e) { throw new RuntimeException(e); } }
public TokenValidation validateToken( KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, AccessToken oldToken, HttpHeaders headers) throws OAuthErrorException { UserModel user = session.users().getUserById(oldToken.getSubject(), realm); if (user == null) { throw new OAuthErrorException( OAuthErrorException.INVALID_GRANT, "Invalid refresh token", "Unknown user"); } if (!user.isEnabled()) { throw new OAuthErrorException( OAuthErrorException.INVALID_GRANT, "User disabled", "User disabled"); } UserSessionModel userSession = session.sessions().getUserSession(realm, oldToken.getSessionState()); if (!AuthenticationManager.isSessionValid(realm, userSession)) { AuthenticationManager.backchannelLogout( session, realm, userSession, uriInfo, connection, headers, true); throw new OAuthErrorException( OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active"); } ClientSessionModel clientSession = null; for (ClientSessionModel clientSessionModel : userSession.getClientSessions()) { if (clientSessionModel.getId().equals(oldToken.getClientSession())) { clientSession = clientSessionModel; break; } } if (clientSession == null) { throw new OAuthErrorException( OAuthErrorException.INVALID_GRANT, "Client session not active", "Client session not active"); } ClientModel client = clientSession.getClient(); if (!client.getClientId().equals(oldToken.getIssuedFor())) { throw new OAuthErrorException( OAuthErrorException.INVALID_GRANT, "Unmatching clients", "Unmatching clients"); } if (oldToken.getIssuedAt() < client.getNotBefore()) { throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token"); } if (oldToken.getIssuedAt() < realm.getNotBefore()) { throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token"); } // recreate token. Set<RoleModel> requestedRoles = TokenManager.getAccess(null, clientSession.getClient(), user); AccessToken newToken = createClientAccessToken( session, requestedRoles, realm, client, user, userSession, clientSession); verifyAccess(oldToken, newToken); return new TokenValidation(user, userSession, clientSession, newToken); }
@Override public String getClientId() { if (updated != null) return updated.getClientId(); return cached.getClientId(); }