Require user to specify a temporary admin password to do admin recovery.
This commit is contained in:
parent
e48aafd588
commit
e977a363ef
5 changed files with 72 additions and 13 deletions
|
@ -5,11 +5,11 @@
|
|||
accidentally deleted, its role mappings were removed, or the password was simply forgotten.
|
||||
</para>
|
||||
<para>
|
||||
To recover the master admin user, just start the server with the following system property:
|
||||
To recover the master admin user, just start the server with the following system properties:
|
||||
<programlisting><![CDATA[
|
||||
bin/standalone.sh -Dkeycloak.recover-admin=true
|
||||
bin/standalone.sh -Dkeycloak.recover-admin=true -Dkeycloak.temp-admin-password=temppassword
|
||||
]]></programlisting>
|
||||
Then you can log in to the master admin account with the default password "admin". You will then be
|
||||
Then you can log in to the master admin account with your temporary password. You will then be
|
||||
prompted to immediately change this password.
|
||||
</para>
|
||||
</chapter>
|
|
@ -36,6 +36,7 @@ public class AdminRecovery {
|
|||
private static final Logger log = Logger.getLogger(AdminRecovery.class);
|
||||
|
||||
public static final String RECOVER_ADMIN_ACCOUNT = "keycloak.recover-admin";
|
||||
public static final String TEMP_ADMIN_PASSWORD = "keycloak.temp-admin-password";
|
||||
|
||||
// Don't allow instances
|
||||
private AdminRecovery() {}
|
||||
|
@ -47,14 +48,15 @@ public class AdminRecovery {
|
|||
|
||||
session.getTransaction().begin();
|
||||
try {
|
||||
doRecover(session);
|
||||
doRecover(session, getTempAdminPassword());
|
||||
session.getTransaction().commit();
|
||||
log.info("*******************************");
|
||||
log.info("Recovered Master Admin account.");
|
||||
log.info("*******************************");
|
||||
} finally {
|
||||
session.close();
|
||||
System.setProperty(AdminRecovery.RECOVER_ADMIN_ACCOUNT, "false");
|
||||
System.clearProperty(RECOVER_ADMIN_ACCOUNT);
|
||||
System.clearProperty(TEMP_ADMIN_PASSWORD);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +65,15 @@ public class AdminRecovery {
|
|||
return Boolean.parseBoolean(strNeedRecovery);
|
||||
}
|
||||
|
||||
private static void doRecover(KeycloakSession session) {
|
||||
private static String getTempAdminPassword() {
|
||||
String tempAdminPassword = System.getProperty(TEMP_ADMIN_PASSWORD);
|
||||
if ((tempAdminPassword == null) || tempAdminPassword.isEmpty()) {
|
||||
throw new OfflineConfigException("Must provide temporary admin password to recover admin account.");
|
||||
}
|
||||
return tempAdminPassword;
|
||||
}
|
||||
|
||||
private static void doRecover(KeycloakSession session, String tempAdminPassword) {
|
||||
RealmProvider realmProvider = session.realms();
|
||||
UserProvider userProvider = session.users();
|
||||
|
||||
|
@ -75,6 +85,6 @@ public class AdminRecovery {
|
|||
adminUser = userProvider.addUser(realm, "admin");
|
||||
}
|
||||
|
||||
ApplianceBootstrap.setupAdminUser(session, realm, adminUser);
|
||||
ApplianceBootstrap.setupAdminUser(session, realm, adminUser, tempAdminPassword);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
|
||||
* as indicated by the @author tags. All rights reserved.
|
||||
*
|
||||
* 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.offlineconfig;
|
||||
|
||||
/**
|
||||
* Runtime exception thrown when an offline configuration fails. Offline
|
||||
* configuration is defined as any configuration done before the Keycloak Server
|
||||
* starts accepting requests.
|
||||
*
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2015 Red Hat Inc.
|
||||
*/
|
||||
public class OfflineConfigException extends IllegalStateException {
|
||||
|
||||
public OfflineConfigException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
|
@ -61,15 +61,15 @@ public class ApplianceBootstrap {
|
|||
KeycloakModelUtils.generateRealmKeys(realm);
|
||||
|
||||
UserModel adminUser = session.users().addUser(realm, "admin");
|
||||
setupAdminUser(session, realm, adminUser);
|
||||
setupAdminUser(session, realm, adminUser, "admin");
|
||||
}
|
||||
|
||||
public static void setupAdminUser(KeycloakSession session, RealmModel realm, UserModel adminUser) {
|
||||
public static void setupAdminUser(KeycloakSession session, RealmModel realm, UserModel adminUser, String password) {
|
||||
adminUser.setEnabled(true);
|
||||
UserCredentialModel password = new UserCredentialModel();
|
||||
password.setType(UserCredentialModel.PASSWORD);
|
||||
password.setValue("admin");
|
||||
session.users().updateCredential(realm, adminUser, password);
|
||||
UserCredentialModel usrCredModel = new UserCredentialModel();
|
||||
usrCredModel.setType(UserCredentialModel.PASSWORD);
|
||||
usrCredModel.setValue(password);
|
||||
session.users().updateCredential(realm, adminUser, usrCredModel);
|
||||
adminUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
|
||||
|
||||
RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.keycloak.testsuite.offlineconfig;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
|
@ -27,6 +28,7 @@ import org.keycloak.models.UserCredentialValueModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserModel.RequiredAction;
|
||||
import org.keycloak.offlineconfig.AdminRecovery;
|
||||
import org.keycloak.offlineconfig.OfflineConfigException;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
import org.keycloak.testsuite.rule.WebRule;
|
||||
|
||||
|
@ -42,6 +44,13 @@ public class AdminRecoveryTest {
|
|||
@Rule
|
||||
public WebRule webRule = new WebRule(this);
|
||||
|
||||
// Verifies that system properties were cleared at the end of recovery
|
||||
@After
|
||||
public void verifySysPropsCleared() {
|
||||
Assert.assertNull(System.getProperty(AdminRecovery.RECOVER_ADMIN_ACCOUNT));
|
||||
Assert.assertNull(System.getProperty(AdminRecovery.TEMP_ADMIN_PASSWORD));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdminDeletedRecovery() {
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
|
@ -78,8 +87,16 @@ public class AdminRecoveryTest {
|
|||
Assert.assertNotEquals("forgotten-password", getAdminPassword());
|
||||
}
|
||||
|
||||
@Test(expected = OfflineConfigException.class)
|
||||
public void testAdminRecoveryWithoutPassword() {
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
System.setProperty(AdminRecovery.RECOVER_ADMIN_ACCOUNT, "true");
|
||||
AdminRecovery.recover(session.getKeycloakSessionFactory());
|
||||
}
|
||||
|
||||
private void doAdminRecovery(KeycloakSession session) {
|
||||
System.setProperty(AdminRecovery.RECOVER_ADMIN_ACCOUNT, "true");
|
||||
System.setProperty(AdminRecovery.TEMP_ADMIN_PASSWORD, "foo");
|
||||
AdminRecovery.recover(session.getKeycloakSessionFactory());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue