コード例 #1
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
  /**
   * Update the TOTP for this account.
   *
   * <p>form parameters:
   *
   * <p>totp - otp generated by authenticator totpSecret - totp secret to register
   *
   * @param formData
   * @return
   */
  @Path("totp")
  @POST
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  public Response processTotpUpdate(final MultivaluedMap<String, String> formData) {
    if (auth == null) {
      return login("totp");
    }

    require(AccountRoles.MANAGE_ACCOUNT);

    String action = formData.getFirst("submitAction");
    if (action != null && action.equals("Cancel")) {
      setReferrerOnPage();
      return account.createResponse(AccountPages.TOTP);
    }

    csrfCheck(formData);

    UserModel user = auth.getUser();

    String totp = formData.getFirst("totp");
    String totpSecret = formData.getFirst("totpSecret");

    if (Validation.isBlank(totp)) {
      setReferrerOnPage();
      return account.setError(Messages.MISSING_TOTP).createResponse(AccountPages.TOTP);
    } else if (!CredentialValidation.validOTP(realm, totp, totpSecret)) {
      setReferrerOnPage();
      return account.setError(Messages.INVALID_TOTP).createResponse(AccountPages.TOTP);
    }

    UserCredentialModel credentials = new UserCredentialModel();
    credentials.setType(realm.getOTPPolicy().getType());
    credentials.setValue(totpSecret);
    session.users().updateCredential(realm, user, credentials);

    user.setOtpEnabled(true);

    // to update counter
    UserCredentialModel cred = new UserCredentialModel();
    cred.setType(realm.getOTPPolicy().getType());
    cred.setValue(totp);
    session.users().validCredentials(realm, user, cred);

    event.event(EventType.UPDATE_TOTP).client(auth.getClient()).user(auth.getUser()).success();

    setReferrerOnPage();
    return account.setSuccess(Messages.SUCCESS_TOTP).createResponse(AccountPages.TOTP);
  }
コード例 #2
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
 @Path("log")
 @GET
 public Response logPage() {
   if (auth != null) {
     List<Event> events =
         eventStore
             .createQuery()
             .type(LOG_EVENTS)
             .user(auth.getUser().getId())
             .maxResults(30)
             .getResultList();
     for (Event e : events) {
       if (e.getDetails() != null) {
         Iterator<Map.Entry<String, String>> itr = e.getDetails().entrySet().iterator();
         while (itr.hasNext()) {
           if (!LOG_DETAILS.contains(itr.next().getKey())) {
             itr.remove();
           }
         }
       }
     }
     account.setEvents(events);
   }
   return forwardToPage("log", AccountPages.LOG);
 }
コード例 #3
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
 @Path("sessions")
 @GET
 public Response sessionsPage() {
   if (auth != null) {
     account.setSessions(session.sessions().getUserSessions(realm, auth.getUser()));
   }
   return forwardToPage("sessions", AccountPages.SESSIONS);
 }
コード例 #4
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
  @Path("password")
  @GET
  public Response passwordPage() {
    if (auth != null) {
      account.setPasswordSet(isPasswordSet(auth.getUser()));
    }

    return forwardToPage("password", AccountPages.PASSWORD);
  }
コード例 #5
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
  @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();
  }
コード例 #6
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
  private Response forwardToPage(String path, AccountPages page) {
    if (auth != null) {
      try {
        require(AccountRoles.MANAGE_ACCOUNT);
      } catch (ForbiddenException e) {
        return session
            .getProvider(LoginFormsProvider.class)
            .setError(Messages.NO_ACCESS)
            .createErrorPage();
      }

      setReferrerOnPage();

      return account.createResponse(page);
    } else {
      return login(path);
    }
  }
コード例 #7
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
  @Path("totp-remove")
  @GET
  public Response processTotpRemove(@QueryParam("stateChecker") String stateChecker) {
    if (auth == null) {
      return login("totp");
    }

    require(AccountRoles.MANAGE_ACCOUNT);

    csrfCheck(stateChecker);

    UserModel user = auth.getUser();
    user.setOtpEnabled(false);

    event.event(EventType.REMOVE_TOTP).client(auth.getClient()).user(auth.getUser()).success();

    setReferrerOnPage();
    return account.setSuccess(Messages.SUCCESS_TOTP_REMOVED).createResponse(AccountPages.TOTP);
  }
コード例 #8
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
  @Path("federated-identity-update")
  @GET
  public Response processFederatedIdentityUpdate(
      @QueryParam("action") String action,
      @QueryParam("provider_id") String providerId,
      @QueryParam("stateChecker") String stateChecker) {
    if (auth == null) {
      return login("identity");
    }

    require(AccountRoles.MANAGE_ACCOUNT);
    csrfCheck(stateChecker);
    UserModel user = auth.getUser();

    if (Validation.isEmpty(providerId)) {
      setReferrerOnPage();
      return account
          .setError(Messages.MISSING_IDENTITY_PROVIDER)
          .createResponse(AccountPages.FEDERATED_IDENTITY);
    }
    AccountSocialAction accountSocialAction = AccountSocialAction.getAction(action);
    if (accountSocialAction == null) {
      setReferrerOnPage();
      return account
          .setError(Messages.INVALID_FEDERATED_IDENTITY_ACTION)
          .createResponse(AccountPages.FEDERATED_IDENTITY);
    }

    boolean hasProvider = false;

    for (IdentityProviderModel model : realm.getIdentityProviders()) {
      if (model.getAlias().equals(providerId)) {
        hasProvider = true;
      }
    }

    if (!hasProvider) {
      setReferrerOnPage();
      return account
          .setError(Messages.IDENTITY_PROVIDER_NOT_FOUND)
          .createResponse(AccountPages.FEDERATED_IDENTITY);
    }

    if (!user.isEnabled()) {
      setReferrerOnPage();
      return account
          .setError(Messages.ACCOUNT_DISABLED)
          .createResponse(AccountPages.FEDERATED_IDENTITY);
    }

    switch (accountSocialAction) {
      case ADD:
        String redirectUri =
            UriBuilder.fromUri(
                    Urls.accountFederatedIdentityPage(uriInfo.getBaseUri(), realm.getName()))
                .build()
                .toString();

        try {
          ClientSessionModel clientSession = auth.getClientSession();
          ClientSessionCode clientSessionCode = new ClientSessionCode(realm, clientSession);
          clientSessionCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
          clientSession.setRedirectUri(redirectUri);
          clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, UUID.randomUUID().toString());

          return Response.temporaryRedirect(
                  Urls.identityProviderAuthnRequest(
                      this.uriInfo.getBaseUri(),
                      providerId,
                      realm.getName(),
                      clientSessionCode.getCode()))
              .build();
        } catch (Exception spe) {
          setReferrerOnPage();
          return account
              .setError(Messages.IDENTITY_PROVIDER_REDIRECT_ERROR)
              .createResponse(AccountPages.FEDERATED_IDENTITY);
        }
      case REMOVE:
        FederatedIdentityModel link = session.users().getFederatedIdentity(user, providerId, realm);
        if (link != null) {

          // Removing last social provider is not possible if you don't have other possibility to
          // authenticate
          if (session.users().getFederatedIdentities(user, realm).size() > 1
              || user.getFederationLink() != null
              || isPasswordSet(user)) {
            session.users().removeFederatedIdentity(realm, user, providerId);

            logger.debugv(
                "Social provider {0} removed successfully from user {1}",
                providerId, user.getUsername());

            event
                .event(EventType.REMOVE_FEDERATED_IDENTITY)
                .client(auth.getClient())
                .user(auth.getUser())
                .detail(Details.USERNAME, link.getUserId() + "@" + link.getIdentityProvider())
                .success();

            setReferrerOnPage();
            return account
                .setSuccess(Messages.IDENTITY_PROVIDER_REMOVED)
                .createResponse(AccountPages.FEDERATED_IDENTITY);
          } else {
            setReferrerOnPage();
            return account
                .setError(Messages.FEDERATED_IDENTITY_REMOVING_LAST_PROVIDER)
                .createResponse(AccountPages.FEDERATED_IDENTITY);
          }
        } else {
          setReferrerOnPage();
          return account
              .setError(Messages.FEDERATED_IDENTITY_NOT_ACTIVE)
              .createResponse(AccountPages.FEDERATED_IDENTITY);
        }
      default:
        throw new IllegalArgumentException();
    }
  }
コード例 #9
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
  /**
   * Update account password
   *
   * <p>Form params:
   *
   * <p>password - old password password-new pasword-confirm
   *
   * @param formData
   * @return
   */
  @Path("password")
  @POST
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  public Response processPasswordUpdate(final MultivaluedMap<String, String> formData) {
    if (auth == null) {
      return login("password");
    }

    require(AccountRoles.MANAGE_ACCOUNT);

    String action = formData.getFirst("submitAction");
    if (action != null && action.equals("Cancel")) {
      setReferrerOnPage();
      return account.createResponse(AccountPages.PASSWORD);
    }

    csrfCheck(formData);
    UserModel user = auth.getUser();

    boolean requireCurrent = isPasswordSet(user);
    account.setPasswordSet(requireCurrent);

    String password = formData.getFirst("password");
    String passwordNew = formData.getFirst("password-new");
    String passwordConfirm = formData.getFirst("password-confirm");

    if (requireCurrent) {
      if (Validation.isBlank(password)) {
        setReferrerOnPage();
        return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD);
      }

      UserCredentialModel cred = UserCredentialModel.password(password);
      if (!session.users().validCredentials(realm, user, cred)) {
        setReferrerOnPage();
        return account
            .setError(Messages.INVALID_PASSWORD_EXISTING)
            .createResponse(AccountPages.PASSWORD);
      }
    }

    if (Validation.isEmpty(passwordNew)) {
      setReferrerOnPage();
      return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD);
    }

    if (!passwordNew.equals(passwordConfirm)) {
      setReferrerOnPage();
      return account
          .setError(Messages.INVALID_PASSWORD_CONFIRM)
          .createResponse(AccountPages.PASSWORD);
    }

    try {
      session.users().updateCredential(realm, user, UserCredentialModel.password(passwordNew));
    } catch (ModelReadOnlyException mre) {
      setReferrerOnPage();
      return account.setError(Messages.READ_ONLY_PASSWORD).createResponse(AccountPages.PASSWORD);
    } catch (ModelException me) {
      logger.error("Failed to update password", me);
      setReferrerOnPage();
      return account
          .setError(me.getMessage(), me.getParameters())
          .createResponse(AccountPages.PASSWORD);
    } catch (Exception ape) {
      logger.error("Failed to update password", ape);
      setReferrerOnPage();
      return account.setError(ape.getMessage()).createResponse(AccountPages.PASSWORD);
    }

    List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, user);
    for (UserSessionModel s : sessions) {
      if (!s.getId().equals(auth.getSession().getId())) {
        AuthenticationManager.backchannelLogout(
            session, realm, s, uriInfo, clientConnection, headers, true);
      }
    }

    event.event(EventType.UPDATE_PASSWORD).client(auth.getClient()).user(auth.getUser()).success();

    setReferrerOnPage();
    return account
        .setPasswordSet(true)
        .setSuccess(Messages.ACCOUNT_PASSWORD_UPDATED)
        .createResponse(AccountPages.PASSWORD);
  }
コード例 #10
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
  /**
   * Update account information.
   *
   * <p>Form params:
   *
   * <p>firstName lastName email
   *
   * @param formData
   * @return
   */
  @Path("/")
  @POST
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  public Response processAccountUpdate(final MultivaluedMap<String, String> formData) {
    if (auth == null) {
      return login(null);
    }

    require(AccountRoles.MANAGE_ACCOUNT);

    String action = formData.getFirst("submitAction");
    if (action != null && action.equals("Cancel")) {
      setReferrerOnPage();
      return account.createResponse(AccountPages.ACCOUNT);
    }

    csrfCheck(formData);

    UserModel user = auth.getUser();

    List<FormMessage> errors = Validation.validateUpdateProfileForm(realm, formData);
    if (errors != null && !errors.isEmpty()) {
      setReferrerOnPage();
      return account
          .setErrors(errors)
          .setProfileFormData(formData)
          .createResponse(AccountPages.ACCOUNT);
    }

    try {
      if (realm.isEditUsernameAllowed()) {
        String username = formData.getFirst("username");

        UserModel existing = session.users().getUserByUsername(username, realm);
        if (existing != null && !existing.getId().equals(user.getId())) {
          throw new ModelDuplicateException(Messages.USERNAME_EXISTS);
        }

        user.setUsername(username);
      }
      user.setFirstName(formData.getFirst("firstName"));
      user.setLastName(formData.getFirst("lastName"));

      String email = formData.getFirst("email");
      String oldEmail = user.getEmail();
      boolean emailChanged = oldEmail != null ? !oldEmail.equals(email) : email != null;
      if (emailChanged) {
        UserModel existing = session.users().getUserByEmail(email, realm);
        if (existing != null && !existing.getId().equals(user.getId())) {
          throw new ModelDuplicateException(Messages.EMAIL_EXISTS);
        }
      }

      user.setEmail(email);

      AttributeFormDataProcessor.process(formData, realm, user);

      event.event(EventType.UPDATE_PROFILE).client(auth.getClient()).user(auth.getUser()).success();

      if (emailChanged) {
        user.setEmailVerified(false);
        event
            .clone()
            .event(EventType.UPDATE_EMAIL)
            .detail(Details.PREVIOUS_EMAIL, oldEmail)
            .detail(Details.UPDATED_EMAIL, email)
            .success();
      }
      setReferrerOnPage();
      return account.setSuccess(Messages.ACCOUNT_UPDATED).createResponse(AccountPages.ACCOUNT);
    } catch (ModelReadOnlyException roe) {
      setReferrerOnPage();
      return account
          .setError(Messages.READ_ONLY_USER)
          .setProfileFormData(formData)
          .createResponse(AccountPages.ACCOUNT);
    } catch (ModelDuplicateException mde) {
      setReferrerOnPage();
      return account
          .setError(mde.getMessage())
          .setProfileFormData(formData)
          .createResponse(AccountPages.ACCOUNT);
    }
  }
コード例 #11
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
 protected void setReferrerOnPage() {
   String[] referrer = getReferrer();
   if (referrer != null) {
     account.setReferrer(referrer);
   }
 }
コード例 #12
0
ファイル: AccountService.java プロジェクト: rishiHPE/keycloak
  public void init() {
    eventStore = session.getProvider(EventStoreProvider.class);

    account =
        session
            .getProvider(AccountProvider.class)
            .setRealm(realm)
            .setUriInfo(uriInfo)
            .setHttpHeaders(headers);

    AuthenticationManager.AuthResult authResult =
        authManager.authenticateBearerToken(session, realm, uriInfo, clientConnection, headers);
    if (authResult != null) {
      auth =
          new Auth(
              realm,
              authResult.getToken(),
              authResult.getUser(),
              client,
              authResult.getSession(),
              false);
    } else {
      authResult = authManager.authenticateIdentityCookie(session, realm);
      if (authResult != null) {
        auth =
            new Auth(
                realm,
                authResult.getToken(),
                authResult.getUser(),
                client,
                authResult.getSession(),
                true);
        updateCsrfChecks();
        account.setStateChecker(stateChecker);
      }
    }

    String requestOrigin = UriUtils.getOrigin(uriInfo.getBaseUri());

    // don't allow cors requests unless they were authenticated by an access token
    // This is to prevent CSRF attacks.
    if (auth != null && auth.isCookieAuthenticated()) {
      String origin = headers.getRequestHeaders().getFirst("Origin");
      if (origin != null && !requestOrigin.equals(origin)) {
        throw new ForbiddenException();
      }

      if (!request.getHttpMethod().equals("GET")) {
        String referrer = headers.getRequestHeaders().getFirst("Referer");
        if (referrer != null && !requestOrigin.equals(UriUtils.getOrigin(referrer))) {
          throw new ForbiddenException();
        }
      }
    }

    if (authResult != null) {
      UserSessionModel userSession = authResult.getSession();
      if (userSession != null) {
        boolean associated = false;
        for (ClientSessionModel c : userSession.getClientSessions()) {
          if (c.getClient().equals(client)) {
            auth.setClientSession(c);
            associated = true;
            break;
          }
        }
        if (!associated) {
          ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
          clientSession.setUserSession(userSession);
          auth.setClientSession(clientSession);
        }
      }

      account.setUser(auth.getUser());
    }

    boolean eventsEnabled = eventStore != null && realm.isEventsEnabled();

    // todo find out from federation if password is updatable
    account.setFeatures(realm.isIdentityFederationEnabled(), eventsEnabled, true);
  }