/**
  * Endpoint for executing reset credentials flow. If code is null, a client session is created
  * with the account service as the client. Successful reset sends you to the account page. Note,
  * account service must be enabled.
  *
  * @param code
  * @param execution
  * @return
  */
 @Path(RESET_CREDENTIALS_PATH)
 @GET
 public Response resetCredentialsGET(
     @QueryParam("code") String code, @QueryParam("execution") String execution) {
   // we allow applications to link to reset credentials without going through OAuth or SAML
   // handshakes
   //
   if (code == null) {
     if (!realm.isResetPasswordAllowed()) {
       event.event(EventType.RESET_PASSWORD);
       event.error(Errors.NOT_ALLOWED);
       return ErrorPage.error(session, Messages.RESET_CREDENTIAL_NOT_ALLOWED);
     }
     // set up the account service as the endpoint to call.
     ClientModel client = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID);
     ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
     clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
     clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
     // clientSession.setNote(AuthenticationManager.END_AFTER_REQUIRED_ACTIONS, "true");
     clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL);
     String redirectUri =
         Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName()).toString();
     clientSession.setRedirectUri(redirectUri);
     clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
     clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
     clientSession.setNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, OAuth2Constants.CODE);
     clientSession.setNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUri);
     clientSession.setNote(
         OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
     return processResetCredentials(null, clientSession, null);
   }
   return resetCredentials(code, execution);
 }
Exemple #2
0
  @GET
  @Path("clients/{client}")
  @Produces(MediaType.TEXT_HTML)
  public Response idpInitiatedSSO(
      @PathParam("client") String clientUrlName, @QueryParam("RelayState") String relayState) {
    event.event(EventType.LOGIN);
    CacheControlUtil.noBackButtonCacheControlHeader();
    ClientModel client = null;
    for (ClientModel c : realm.getClients()) {
      String urlName = c.getAttribute(SamlProtocol.SAML_IDP_INITIATED_SSO_URL_NAME);
      if (urlName == null) continue;
      if (urlName.equals(clientUrlName)) {
        client = c;
        break;
      }
    }
    if (client == null) {
      event.error(Errors.CLIENT_NOT_FOUND);
      return ErrorPage.error(session, Messages.CLIENT_NOT_FOUND);
    }
    if (client.getManagementUrl() == null
        && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE) == null
        && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE)
            == null) {
      logger.error("SAML assertion consumer url not set up");
      event.error(Errors.INVALID_REDIRECT_URI);
      return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI);
    }

    String bindingType = SamlProtocol.SAML_POST_BINDING;
    if (client.getManagementUrl() == null
        && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE) == null
        && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE)
            != null) {
      bindingType = SamlProtocol.SAML_REDIRECT_BINDING;
    }

    String redirect = null;
    if (bindingType.equals(SamlProtocol.SAML_REDIRECT_BINDING)) {
      redirect = client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE);
    } else {
      redirect = client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE);
    }
    if (redirect == null) {
      redirect = client.getManagementUrl();
    }

    ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
    clientSession.setAuthMethod(SamlProtocol.LOGIN_PROTOCOL);
    clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
    clientSession.setNote(SamlProtocol.SAML_BINDING, SamlProtocol.SAML_POST_BINDING);
    clientSession.setNote(SamlProtocol.SAML_IDP_INITIATED_LOGIN, "true");
    clientSession.setRedirectUri(redirect);

    if (relayState == null) {
      relayState = client.getAttribute(SamlProtocol.SAML_IDP_INITIATED_SSO_RELAY_STATE);
    }
    if (relayState != null && !relayState.trim().equals("")) {
      clientSession.setNote(GeneralConstants.RELAY_STATE, relayState);
    }

    return newBrowserAuthentication(clientSession, false, false);
  }
Exemple #3
0
    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);
      }
    }
Exemple #4
0
    protected Response loginRequest(
        String relayState, AuthnRequestType requestAbstractType, ClientModel client) {
      SamlClient samlClient = new SamlClient(client);
      // validate destination
      if (requestAbstractType.getDestination() != null
          && !uriInfo.getAbsolutePath().equals(requestAbstractType.getDestination())) {
        event.detail(Details.REASON, "invalid_destination");
        event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
        return ErrorPage.error(session, Messages.INVALID_REQUEST);
      }
      String bindingType = getBindingType(requestAbstractType);
      if (samlClient.forcePostBinding()) bindingType = SamlProtocol.SAML_POST_BINDING;
      String redirect = null;
      URI redirectUri = requestAbstractType.getAssertionConsumerServiceURL();
      if (redirectUri != null && !"null".equals(redirectUri)) { // "null" is for testing purposes
        redirect = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri.toString(), realm, client);
      } else {
        if (bindingType.equals(SamlProtocol.SAML_POST_BINDING)) {
          redirect = client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE);
        } else {
          redirect =
              client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE);
        }
        if (redirect == null) {
          redirect = client.getManagementUrl();
        }
      }

      if (redirect == null) {
        event.error(Errors.INVALID_REDIRECT_URI);
        return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI);
      }

      ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
      clientSession.setAuthMethod(SamlProtocol.LOGIN_PROTOCOL);
      clientSession.setRedirectUri(redirect);
      clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
      clientSession.setNote(SamlProtocol.SAML_BINDING, bindingType);
      clientSession.setNote(GeneralConstants.RELAY_STATE, relayState);
      clientSession.setNote(SamlProtocol.SAML_REQUEST_ID, requestAbstractType.getID());

      // Handle NameIDPolicy from SP
      NameIDPolicyType nameIdPolicy = requestAbstractType.getNameIDPolicy();
      if (nameIdPolicy != null && !samlClient.forceNameIDFormat()) {
        String nameIdFormat = nameIdPolicy.getFormat().toString();
        // TODO: Handle AllowCreate too, relevant for persistent NameID.
        if (isSupportedNameIdFormat(nameIdFormat)) {
          clientSession.setNote(GeneralConstants.NAMEID_FORMAT, nameIdFormat);
        } else {
          event.detail(Details.REASON, "unsupported_nameid_format");
          event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
          return ErrorPage.error(session, Messages.UNSUPPORTED_NAME_ID_FORMAT);
        }
      }

      // Reading subject/nameID in the saml request
      SubjectType subject = requestAbstractType.getSubject();
      if (subject != null) {
        SubjectType.STSubType subType = subject.getSubType();
        if (subType != null) {
          BaseIDAbstractType baseID = subject.getSubType().getBaseID();
          if (baseID != null && baseID instanceof NameIDType) {
            NameIDType nameID = (NameIDType) baseID;
            clientSession.setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, nameID.getValue());
          }
        }
      }

      return newBrowserAuthentication(
          clientSession, requestAbstractType.isIsPassive(), redirectToAuthentication);
    }