Merge pull request #1261 from panga/master
KEYCLOAK-1306 - Better Admin API error handling (new)
This commit is contained in:
commit
c193ba0c81
11 changed files with 195 additions and 4 deletions
|
@ -0,0 +1,8 @@
|
||||||
|
invalidPasswordMinLengthMessage=Invalid password: minimum length {0}.
|
||||||
|
invalidPasswordMinLowerCaseCharsMessage=Invalid password: must contain at least {0} lower case characters.
|
||||||
|
invalidPasswordMinDigitsMessage=Invalid password: must contain at least {0} numerical digits.
|
||||||
|
invalidPasswordMinUpperCaseCharsMessage=Invalid password: must contain at least {0} upper case characters.
|
||||||
|
invalidPasswordMinSpecialCharsMessage=Invalid password: must contain at least {0} special characters.
|
||||||
|
invalidPasswordNotUsernameMessage=Invalid password: must not be equal to the username.
|
||||||
|
invalidPasswordRegexPatternMessage=Invalid password: fails to match regex pattern(s).
|
||||||
|
invalidPasswordHistoryMessage=Invalid password: must not be equal to any of last {0} passwords.
|
|
@ -308,8 +308,12 @@ module.controller('UserCredentialsCtrl', function($scope, realm, user, User, Use
|
||||||
Notifications.success("The password has been reset");
|
Notifications.success("The password has been reset");
|
||||||
$scope.password = null;
|
$scope.password = null;
|
||||||
$scope.confirmPassword = null;
|
$scope.confirmPassword = null;
|
||||||
}, function() {
|
}, function(response) {
|
||||||
|
if (response.data && response.data.errorMessage) {
|
||||||
|
Notifications.error(response.data.errorMessage);
|
||||||
|
} else {
|
||||||
Notifications.error("Failed to reset user password");
|
Notifications.error("Failed to reset user password");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}, function() {
|
}, function() {
|
||||||
$scope.password = null;
|
$scope.password = null;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package org.keycloak.messages;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:leonardo.zanivan@gmail.com">Leonardo Zanivan</a>
|
||||||
|
*/
|
||||||
|
public interface MessagesProvider extends Provider {
|
||||||
|
|
||||||
|
String getMessage(String messageKey, Object... parameters);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.keycloak.messages;
|
||||||
|
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:leonardo.zanivan@gmail.com">Leonardo Zanivan</a>
|
||||||
|
*/
|
||||||
|
public interface MessagesProviderFactory extends ProviderFactory<MessagesProvider> {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package org.keycloak.messages;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
import org.keycloak.provider.Spi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:leonardo.zanivan@gmail.com">Leonardo Zanivan</a>
|
||||||
|
*/
|
||||||
|
public class MessagesSpi implements Spi {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPrivate() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "messages";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Provider> getProviderClass() {
|
||||||
|
return MessagesProvider.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||||
|
return MessagesProviderFactory.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package org.keycloak.services.messages;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Properties;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.messages.MessagesProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:leonardo.zanivan@gmail.com">Leonardo Zanivan</a>
|
||||||
|
*/
|
||||||
|
public class AdminMessagesProvider implements MessagesProvider {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(AdminMessagesProvider.class);
|
||||||
|
|
||||||
|
private KeycloakSession session;
|
||||||
|
private Locale locale;
|
||||||
|
private Properties messagesBundle;
|
||||||
|
|
||||||
|
public AdminMessagesProvider(KeycloakSession session, Locale locale) {
|
||||||
|
this.session = session;
|
||||||
|
this.locale = locale;
|
||||||
|
this.messagesBundle = getMessagesBundle(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage(String messageKey, Object... parameters) {
|
||||||
|
String message = messagesBundle.getProperty(messageKey, messageKey);
|
||||||
|
return new MessageFormat(message, locale).format(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private Properties getMessagesBundle(Locale locale) {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
|
||||||
|
if (locale == null) {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
URL url = getClass().getClassLoader().getResource(
|
||||||
|
"theme/base/admin/messages/messages_" + locale.toString() + ".properties");
|
||||||
|
if (url != null) {
|
||||||
|
try {
|
||||||
|
properties.load(url.openStream());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.warn("Failed to load messages", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package org.keycloak.services.messages;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.messages.MessagesProvider;
|
||||||
|
import org.keycloak.messages.MessagesProviderFactory;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:leonardo.zanivan@gmail.com">Leonardo Zanivan</a>
|
||||||
|
*/
|
||||||
|
public class AdminMessagesProviderFactory implements MessagesProviderFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MessagesProvider create(KeycloakSession session) {
|
||||||
|
return new AdminMessagesProvider(session, Locale.ENGLISH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postInit(KeycloakSessionFactory factory) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "admin";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -39,7 +39,6 @@ import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
@ -75,6 +74,7 @@ public class KeycloakApplication extends Application {
|
||||||
singletons.add(new ServerVersionResource());
|
singletons.add(new ServerVersionResource());
|
||||||
singletons.add(new RealmsResource());
|
singletons.add(new RealmsResource());
|
||||||
singletons.add(new AdminRoot());
|
singletons.add(new AdminRoot());
|
||||||
|
singletons.add(new ModelExceptionMapper());
|
||||||
classes.add(SkeletonKeyContextResolver.class);
|
classes.add(SkeletonKeyContextResolver.class);
|
||||||
classes.add(QRCodeResource.class);
|
classes.add(QRCodeResource.class);
|
||||||
classes.add(ThemeResource.class);
|
classes.add(ThemeResource.class);
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package org.keycloak.services.resources;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.ext.ExceptionMapper;
|
||||||
|
import javax.ws.rs.ext.Provider;
|
||||||
|
import org.keycloak.messages.MessagesProvider;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.ModelException;
|
||||||
|
import org.keycloak.services.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:leonardo.zanivan@gmail.com">Leonardo Zanivan</a>
|
||||||
|
*/
|
||||||
|
@Provider
|
||||||
|
public class ModelExceptionMapper implements ExceptionMapper<ModelException> {
|
||||||
|
|
||||||
|
@Context
|
||||||
|
private KeycloakSession session;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response toResponse(ModelException ex) {
|
||||||
|
String message = session.getProvider(MessagesProvider.class, "admin")
|
||||||
|
.getMessage(ex.getMessage(), ex.getParameters());
|
||||||
|
return ErrorResponse.error(message, Response.Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.services.messages.AdminMessagesProviderFactory
|
|
@ -2,3 +2,4 @@ org.keycloak.protocol.LoginProtocolSpi
|
||||||
org.keycloak.protocol.ProtocolMapperSpi
|
org.keycloak.protocol.ProtocolMapperSpi
|
||||||
org.keycloak.exportimport.ClientImportSpi
|
org.keycloak.exportimport.ClientImportSpi
|
||||||
org.keycloak.wellknown.WellKnownSpi
|
org.keycloak.wellknown.WellKnownSpi
|
||||||
|
org.keycloak.messages.MessagesSpi
|
Loading…
Reference in a new issue