@Override public Response frontchannelLogout( UserSessionModel userSession, ClientSessionModel clientSession) { ClientModel client = clientSession.getClient(); SamlClient samlClient = new SamlClient(client); if (!(client instanceof ClientModel)) return null; try { if (isLogoutPostBindingForClient(clientSession)) { String bindingUri = getLogoutServiceUrl(uriInfo, client, SAML_POST_BINDING); SAML2LogoutRequestBuilder logoutBuilder = createLogoutRequest(bindingUri, clientSession, client); JaxrsSAML2BindingBuilder binding = createBindingBuilder(samlClient); return binding.postBinding(logoutBuilder.buildDocument()).request(bindingUri); } else { logger.debug("frontchannel redirect binding"); String bindingUri = getLogoutServiceUrl(uriInfo, client, SAML_REDIRECT_BINDING); SAML2LogoutRequestBuilder logoutBuilder = createLogoutRequest(bindingUri, clientSession, client); JaxrsSAML2BindingBuilder binding = createBindingBuilder(samlClient); return binding.redirectBinding(logoutBuilder.buildDocument()).request(bindingUri); } } catch (ConfigurationException e) { throw new RuntimeException(e); } catch (ProcessingException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } catch (ParsingException e) { throw new RuntimeException(e); } }
@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; } }
protected Response buildErrorResponse( ClientSessionModel clientSession, JaxrsSAML2BindingBuilder binding, Document document) throws ConfigurationException, ProcessingException, IOException { if (isPostBinding(clientSession)) { return binding.postBinding(document).response(clientSession.getRedirectUri()); } else { return binding.redirectBinding(document).response(clientSession.getRedirectUri()); } }
protected Response buildLogoutResponse( UserSessionModel userSession, String logoutBindingUri, SAML2LogoutResponseBuilder builder, JaxrsSAML2BindingBuilder binding) throws ConfigurationException, ProcessingException, IOException { if (isLogoutPostBindingForInitiator(userSession)) { return binding.postBinding(builder.buildDocument()).response(logoutBindingUri); } else { return binding.redirectBinding(builder.buildDocument()).response(logoutBindingUri); } }
protected Response buildAuthenticatedResponse( ClientSessionModel clientSession, String redirectUri, Document samlDocument, JaxrsSAML2BindingBuilder bindingBuilder) throws ConfigurationException, ProcessingException, IOException { if (isPostBinding(clientSession)) { return bindingBuilder.postBinding(samlDocument).response(redirectUri); } else { return bindingBuilder.redirectBinding(samlDocument).response(redirectUri); } }
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); } }