protected SAML2LogoutRequestBuilder createLogoutRequest( String logoutUrl, ClientSessionModel clientSession, ClientModel client) { // build userPrincipal with subject used at login SAML2LogoutRequestBuilder logoutBuilder = new SAML2LogoutRequestBuilder() .assertionExpiration(realm.getAccessCodeLifespan()) .issuer(getResponseIssuer(realm)) .sessionIndex(clientSession.getId()) .userPrincipal( clientSession.getNote(SAML_NAME_ID), clientSession.getNote(SAML_NAME_ID_FORMAT)) .destination(logoutUrl); return logoutBuilder; }
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; }
protected boolean isLogoutPostBindingForClient(ClientSessionModel clientSession) { ClientModel client = clientSession.getClient(); SamlClient samlClient = new SamlClient(client); String logoutPostUrl = client.getAttribute(SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE); String logoutRedirectUrl = client.getAttribute(SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE); if (logoutPostUrl == null) { // if we don't have a redirect uri either, return true and default to the admin url + POST // binding if (logoutRedirectUrl == null) return true; return false; } if (samlClient.forcePostBinding()) { return true; // configured to force a post binding and post binding logout url is not null } String bindingType = clientSession.getNote(SAML_BINDING); // if the login binding was POST, return true if (SAML_POST_BINDING.equals(bindingType)) return true; if (logoutRedirectUrl == null) return true; // we don't have a redirect binding url, so use post binding return false; // redirect binding }
private void setupResponseTypeAndMode(ClientSessionModel clientSession) { String responseType = clientSession.getNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM); String responseMode = clientSession.getNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM); this.responseType = OIDCResponseType.parse(responseType); this.responseMode = OIDCResponseMode.parse(responseMode, this.responseType); this.event.detail(Details.RESPONSE_TYPE, responseType); this.event.detail(Details.RESPONSE_MODE, this.responseMode.toString().toLowerCase()); }
protected String getNameIdFormat(SamlClient samlClient, ClientSessionModel clientSession) { String nameIdFormat = clientSession.getNote(GeneralConstants.NAMEID_FORMAT); boolean forceFormat = samlClient.forceNameIDFormat(); String configuredNameIdFormat = samlClient.getNameIDFormat(); if ((nameIdFormat == null || forceFormat) && configuredNameIdFormat != null) { nameIdFormat = configuredNameIdFormat; } if (nameIdFormat == null) return SAML_DEFAULT_NAMEID_FORMAT; return nameIdFormat; }
@Override public Response sendError(ClientSessionModel clientSession, Error error) { setupResponseTypeAndMode(clientSession); String redirect = clientSession.getRedirectUri(); String state = clientSession.getNote(OIDCLoginProtocol.STATE_PARAM); OIDCRedirectUriBuilder redirectUri = OIDCRedirectUriBuilder.fromUri(redirect, responseMode) .addParam(OAuth2Constants.ERROR, translateError(error)); if (state != null) redirectUri.addParam(OAuth2Constants.STATE, state); session.sessions().removeClientSession(realm, clientSession); RestartLoginCookie.expireRestartCookie(realm, session.getContext().getConnection(), uriInfo); return redirectUri.build(); }
@Override public Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode) { ClientSessionModel clientSession = accessCode.getClientSession(); setupResponseTypeAndMode(clientSession); String redirect = clientSession.getRedirectUri(); OIDCRedirectUriBuilder redirectUri = OIDCRedirectUriBuilder.fromUri(redirect, responseMode); String state = clientSession.getNote(OIDCLoginProtocol.STATE_PARAM); logger.debugv("redirectAccessCode: state: {0}", state); if (state != null) redirectUri.addParam(OAuth2Constants.STATE, state); // Standard or hybrid flow if (responseType.hasResponseType(OIDCResponseType.CODE)) { accessCode.setAction(ClientSessionModel.Action.CODE_TO_TOKEN.name()); redirectUri.addParam(OAuth2Constants.CODE, accessCode.getCode()); } // Implicit or hybrid flow if (responseType.isImplicitOrHybridFlow()) { TokenManager tokenManager = new TokenManager(); AccessTokenResponse res = tokenManager .responseBuilder( realm, clientSession.getClient(), event, session, userSession, clientSession) .generateAccessToken() .generateIDToken() .build(); if (responseType.hasResponseType(OIDCResponseType.ID_TOKEN)) { redirectUri.addParam("id_token", res.getIdToken()); } if (responseType.hasResponseType(OIDCResponseType.TOKEN)) { redirectUri.addParam("access_token", res.getToken()); redirectUri.addParam("token_type", res.getTokenType()); redirectUri.addParam("session-state", res.getSessionState()); redirectUri.addParam("expires_in", String.valueOf(res.getExpiresIn())); } redirectUri.addParam("not-before-policy", String.valueOf(res.getNotBeforePolicy())); } return redirectUri.build(); }
@Override public Response sendError(ClientSessionModel clientSession, Error error) { try { if ("true".equals(clientSession.getClient().getAttribute(SAML_IDP_INITIATED_LOGIN))) { if (error == Error.CANCELLED_BY_USER) { UriBuilder builder = RealmsResource.protocolUrl(uriInfo).path(SamlService.class, "idpInitiatedSSO"); Map<String, String> params = new HashMap<>(); params.put("realm", realm.getName()); params.put("protocol", LOGIN_PROTOCOL); params.put( "client", clientSession.getClient().getAttribute(SAML_IDP_INITIATED_SSO_URL_NAME)); URI redirect = builder.buildFromMap(params); return Response.status(302).location(redirect).build(); } else { return ErrorPage.error(session, translateErrorToIdpInitiatedErrorMessage(error)); } } else { SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder() .destination(clientSession.getRedirectUri()) .issuer(getResponseIssuer(realm)) .status(translateErrorToSAMLStatus(error).get()); try { JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder() .relayState(clientSession.getNote(GeneralConstants.RELAY_STATE)); Document document = builder.buildDocument(); return buildErrorResponse(clientSession, binding, document); } catch (Exception e) { return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE); } } } finally { RestartLoginCookie.expireRestartCookie(realm, session.getContext().getConnection(), uriInfo); session.sessions().removeClientSession(realm, clientSession); } }
private void initEvent(ClientSessionModel clientSession) { event .event(EventType.LOGIN) .client(clientSession.getClient()) .user(clientSession.getUserSession().getUser()) .session(clientSession.getUserSession().getId()) .detail(Details.CODE_ID, clientSession.getId()) .detail(Details.REDIRECT_URI, clientSession.getRedirectUri()) .detail( Details.USERNAME, clientSession.getNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME)) .detail(Details.RESPONSE_TYPE, "code"); UserSessionModel userSession = clientSession.getUserSession(); if (userSession != null) { event.detail(Details.AUTH_METHOD, userSession.getAuthMethod()); event.detail(Details.USERNAME, userSession.getLoginUsername()); if (userSession.isRememberMe()) { event.detail(Details.REMEMBER_ME, "true"); } } }
@Override public Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode) { ClientSessionModel clientSession = accessCode.getClientSession(); ClientModel client = clientSession.getClient(); SamlClient samlClient = new SamlClient(client); String requestID = clientSession.getNote(SAML_REQUEST_ID); String relayState = clientSession.getNote(GeneralConstants.RELAY_STATE); String redirectUri = clientSession.getRedirectUri(); String responseIssuer = getResponseIssuer(realm); String nameIdFormat = getNameIdFormat(samlClient, clientSession); String nameId = getNameId(nameIdFormat, clientSession, userSession); // save NAME_ID and format in clientSession as they may be persistent or transient or email and // not username // we'll need to send this back on a logout clientSession.setNote(SAML_NAME_ID, nameId); clientSession.setNote(SAML_NAME_ID_FORMAT, nameIdFormat); SAML2LoginResponseBuilder builder = new SAML2LoginResponseBuilder(); builder .requestID(requestID) .destination(redirectUri) .issuer(responseIssuer) .assertionExpiration(realm.getAccessCodeLifespan()) .subjectExpiration(realm.getAccessTokenLifespan()) .sessionIndex(clientSession.getId()) .requestIssuer(clientSession.getClient().getClientId()) .nameIdentifier(nameIdFormat, nameId) .authMethod(JBossSAMLURIConstants.AC_UNSPECIFIED.get()); if (!samlClient.includeAuthnStatement()) { builder.disableAuthnStatement(true); } List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers = new LinkedList<>(); List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> loginResponseMappers = new LinkedList<>(); ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper = null; Set<ProtocolMapperModel> mappings = accessCode.getRequestedProtocolMappers(); for (ProtocolMapperModel mapping : mappings) { ProtocolMapper mapper = (ProtocolMapper) session .getKeycloakSessionFactory() .getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper()); if (mapper == null) continue; if (mapper instanceof SAMLAttributeStatementMapper) { attributeStatementMappers.add( new ProtocolMapperProcessor<SAMLAttributeStatementMapper>( (SAMLAttributeStatementMapper) mapper, mapping)); } if (mapper instanceof SAMLLoginResponseMapper) { loginResponseMappers.add( new ProtocolMapperProcessor<SAMLLoginResponseMapper>( (SAMLLoginResponseMapper) mapper, mapping)); } if (mapper instanceof SAMLRoleListMapper) { roleListMapper = new ProtocolMapperProcessor<SAMLRoleListMapper>((SAMLRoleListMapper) mapper, mapping); } } Document samlDocument = null; try { ResponseType samlModel = builder.buildModel(); final AttributeStatementType attributeStatement = populateAttributeStatements( attributeStatementMappers, session, userSession, clientSession); populateRoles(roleListMapper, session, userSession, clientSession, attributeStatement); // SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute if (attributeStatement.getAttributes().size() > 0) { AssertionType assertion = samlModel.getAssertions().get(0).getAssertion(); assertion.addStatement(attributeStatement); } samlModel = transformLoginResponse( loginResponseMappers, samlModel, session, userSession, clientSession); samlDocument = builder.buildDocument(samlModel); } catch (Exception e) { logger.error("failed", e); return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE); } JaxrsSAML2BindingBuilder bindingBuilder = new JaxrsSAML2BindingBuilder(); bindingBuilder.relayState(relayState); KeyManager keyManager = session.keys(); KeyManager.ActiveKey keys = keyManager.getActiveKey(realm); if (samlClient.requiresRealmSignature()) { String canonicalization = samlClient.getCanonicalizationMethod(); if (canonicalization != null) { bindingBuilder.canonicalizationMethod(canonicalization); } bindingBuilder .signatureAlgorithm(samlClient.getSignatureAlgorithm()) .signWith(keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()) .signDocument(); } if (samlClient.requiresAssertionSignature()) { String canonicalization = samlClient.getCanonicalizationMethod(); if (canonicalization != null) { bindingBuilder.canonicalizationMethod(canonicalization); } bindingBuilder .signatureAlgorithm(samlClient.getSignatureAlgorithm()) .signWith(keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()) .signAssertions(); } if (samlClient.requiresEncryption()) { PublicKey publicKey = null; try { publicKey = SamlProtocolUtils.getEncryptionValidationKey(client); } catch (Exception e) { logger.error("failed", e); return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE); } bindingBuilder.encrypt(publicKey); } try { return buildAuthenticatedResponse(clientSession, redirectUri, samlDocument, bindingBuilder); } catch (Exception e) { logger.error("failed", e); return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE); } }
protected boolean isPostBinding(ClientSessionModel clientSession) { ClientModel client = clientSession.getClient(); SamlClient samlClient = new SamlClient(client); return SamlProtocol.SAML_POST_BINDING.equals(clientSession.getNote(SamlProtocol.SAML_BINDING)) || samlClient.forcePostBinding(); }
@GET public Response authResponse( @QueryParam("state") String state, @QueryParam("denied") String denied, @QueryParam("oauth_verifier") String verifier) { try { Twitter twitter = new TwitterFactory().getInstance(); twitter.setOAuthConsumer(getConfig().getClientId(), getConfig().getClientSecret()); ClientSessionModel clientSession = parseClientSessionCode(state).getClientSession(); String twitterToken = clientSession.getNote("twitter_token"); String twitterSecret = clientSession.getNote("twitter_tokenSecret"); RequestToken requestToken = new RequestToken(twitterToken, twitterSecret); AccessToken oAuthAccessToken = twitter.getOAuthAccessToken(requestToken, verifier); twitter4j.User twitterUser = twitter.verifyCredentials(); BrokeredIdentityContext identity = new BrokeredIdentityContext(Long.toString(twitterUser.getId())); identity.setIdp(TwitterIdentityProvider.this); identity.setUsername(twitterUser.getScreenName()); identity.setName(twitterUser.getName()); StringBuilder tokenBuilder = new StringBuilder(); tokenBuilder.append("{"); tokenBuilder .append("\"oauth_token\":") .append("\"") .append(oAuthAccessToken.getToken()) .append("\"") .append(","); tokenBuilder .append("\"oauth_token_secret\":") .append("\"") .append(oAuthAccessToken.getTokenSecret()) .append("\"") .append(","); tokenBuilder .append("\"screen_name\":") .append("\"") .append(oAuthAccessToken.getScreenName()) .append("\"") .append(","); tokenBuilder .append("\"user_id\":") .append("\"") .append(oAuthAccessToken.getUserId()) .append("\""); tokenBuilder.append("}"); identity.setToken(tokenBuilder.toString()); identity.setCode(state); identity.setIdpConfig(getConfig()); return callback.authenticated(identity); } catch (Exception e) { logger.error("Could get user profile from twitter.", e); } EventBuilder event = new EventBuilder(realm, session, clientConnection); event.event(EventType.LOGIN); event.error("twitter_login_failed"); return ErrorPage.error(session, Messages.UNEXPECTED_ERROR_HANDLING_RESPONSE); }