Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
KEYCLOAK-6455 Ability to require email to be verified before changing
- Loading branch information
1 parent
ada7f37
commit cf1596c
Showing
66 changed files
with
1,676 additions
and
301 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo13_0_0.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* Copyright 2021 Red Hat, Inc. and/or its affiliates | ||
* and other contributors as indicated by the @author tags. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.keycloak.migration.migrators; | ||
|
||
import org.keycloak.migration.ModelVersion; | ||
import org.keycloak.models.KeycloakSession; | ||
import org.keycloak.models.utils.DefaultRequiredActions; | ||
|
||
public class MigrateTo13_0_0 implements Migration { | ||
|
||
public static final ModelVersion VERSION = new ModelVersion("13.0.0"); | ||
|
||
@Override | ||
public void migrate(KeycloakSession session) { | ||
session.realms().getRealmsStream().forEach(DefaultRequiredActions::addUpdateEmailAction); | ||
} | ||
|
||
@Override | ||
public ModelVersion getVersion() { | ||
return VERSION; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
*/ | ||
public enum UserUpdateEvent { | ||
UpdateProfile, | ||
UpdateEmail, | ||
UserResource, | ||
Account, | ||
IdpReview, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
...main/java/org/keycloak/authentication/actiontoken/updateemail/UpdateEmailActionToken.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* Copyright 2021 Red Hat, Inc. and/or its affiliates | ||
* and other contributors as indicated by the @author tags. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.keycloak.authentication.actiontoken.updateemail; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import org.keycloak.authentication.actiontoken.DefaultActionToken; | ||
|
||
public class UpdateEmailActionToken extends DefaultActionToken { | ||
|
||
public static final String TOKEN_TYPE = "update-email"; | ||
|
||
@JsonProperty("oldEmail") | ||
private String oldEmail; | ||
@JsonProperty("newEmail") | ||
private String newEmail; | ||
|
||
public UpdateEmailActionToken(String userId, int absoluteExpirationInSecs, String oldEmail, String newEmail){ | ||
super(userId, TOKEN_TYPE, absoluteExpirationInSecs, null); | ||
this.oldEmail = oldEmail; | ||
this.newEmail = newEmail; | ||
} | ||
|
||
private UpdateEmailActionToken(){ | ||
|
||
} | ||
|
||
public String getOldEmail() { | ||
return oldEmail; | ||
} | ||
|
||
public void setOldEmail(String oldEmail) { | ||
this.oldEmail = oldEmail; | ||
} | ||
|
||
public String getNewEmail() { | ||
return newEmail; | ||
} | ||
|
||
public void setNewEmail(String newEmail) { | ||
this.newEmail = newEmail; | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
...va/org/keycloak/authentication/actiontoken/updateemail/UpdateEmailActionTokenHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* | ||
* Copyright 2021 Red Hat, Inc. and/or its affiliates | ||
* and other contributors as indicated by the @author tags. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.keycloak.authentication.actiontoken.updateemail; | ||
|
||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
import javax.ws.rs.core.Response; | ||
|
||
import org.keycloak.TokenVerifier; | ||
import org.keycloak.authentication.actiontoken.AbstractActionTokenHander; | ||
import org.keycloak.authentication.actiontoken.ActionTokenContext; | ||
import org.keycloak.authentication.actiontoken.TokenUtils; | ||
import org.keycloak.authentication.requiredactions.UpdateEmail; | ||
import org.keycloak.events.Errors; | ||
import org.keycloak.events.EventType; | ||
import org.keycloak.forms.login.LoginFormsProvider; | ||
import org.keycloak.models.KeycloakSession; | ||
import org.keycloak.models.UserModel; | ||
import org.keycloak.models.utils.FormMessage; | ||
import org.keycloak.services.messages.Messages; | ||
import org.keycloak.services.validation.Validation; | ||
import org.keycloak.sessions.AuthenticationSessionModel; | ||
import org.keycloak.userprofile.validation.UserProfileValidationResult; | ||
|
||
public class UpdateEmailActionTokenHandler extends AbstractActionTokenHander<UpdateEmailActionToken> { | ||
|
||
public UpdateEmailActionTokenHandler() { | ||
super(UpdateEmailActionToken.TOKEN_TYPE, UpdateEmailActionToken.class, Messages.STALE_VERIFY_EMAIL_LINK, | ||
EventType.EXECUTE_ACTIONS, Errors.INVALID_TOKEN); | ||
} | ||
|
||
@Override | ||
public TokenVerifier.Predicate<? super UpdateEmailActionToken>[] getVerifiers( | ||
ActionTokenContext<UpdateEmailActionToken> tokenContext) { | ||
return TokenUtils.predicates(TokenUtils.checkThat( | ||
t -> Objects.equals(t.getOldEmail(), tokenContext.getAuthenticationSession().getAuthenticatedUser().getEmail()), | ||
Errors.INVALID_EMAIL, getDefaultErrorMessage())); | ||
} | ||
|
||
@Override | ||
public Response handleToken(UpdateEmailActionToken token, ActionTokenContext<UpdateEmailActionToken> tokenContext) { | ||
AuthenticationSessionModel authenticationSession = tokenContext.getAuthenticationSession(); | ||
UserModel user = authenticationSession.getAuthenticatedUser(); | ||
|
||
KeycloakSession session = tokenContext.getSession(); | ||
|
||
LoginFormsProvider forms = session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authenticationSession) | ||
.setUser(user); | ||
|
||
String newEmail = token.getNewEmail(); | ||
|
||
UserProfileValidationResult emailUpdateValidationResult = UpdateEmail.validateEmailUpdate(session, user, newEmail); | ||
List<FormMessage> errors = Validation.getFormErrorsFromValidation(emailUpdateValidationResult); | ||
if (!errors.isEmpty()) { | ||
return forms.setErrors(errors).createErrorPage(Response.Status.BAD_REQUEST); | ||
} | ||
|
||
UpdateEmail.updateEmailNow(tokenContext.getEvent(), tokenContext.getRealm(), user, emailUpdateValidationResult); | ||
|
||
tokenContext.getEvent().success(); | ||
|
||
// verify user email as we know it is valid as this entry point would never have gotten here. | ||
user.setEmailVerified(true); | ||
user.removeRequiredAction(UserModel.RequiredAction.UPDATE_EMAIL); | ||
tokenContext.getAuthenticationSession().removeRequiredAction(UserModel.RequiredAction.UPDATE_EMAIL); | ||
user.removeRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL); | ||
tokenContext.getAuthenticationSession().removeRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL); | ||
|
||
return forms.setAttribute("messageHeader", forms.getMessage("emailUpdatedTitle")).setSuccess("emailUpdated", newEmail) | ||
.createInfoPage(); | ||
} | ||
|
||
@Override | ||
public boolean canUseTokenRepeatedly(UpdateEmailActionToken token, | ||
ActionTokenContext<UpdateEmailActionToken> tokenContext) { | ||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.