summaryrefslogtreecommitdiff
path: root/qpid/java/broker-plugins/management-http/src/main
diff options
context:
space:
mode:
authorAlex Rudyy <orudyy@apache.org>2013-04-08 11:17:41 +0000
committerAlex Rudyy <orudyy@apache.org>2013-04-08 11:17:41 +0000
commitad56a06e1f1c22a0baccb99c27a64ee9564da83b (patch)
treef6c77961e2f1fcb28e0b65368b8b7cc5a9e3ba6b /qpid/java/broker-plugins/management-http/src/main
parentd85edbc941559aa85c5a998bbb8894f13baaf81c (diff)
downloadqpid-python-ad56a06e1f1c22a0baccb99c27a64ee9564da83b.tar.gz
QPID-4705: Restrict access to web management interfaces to authenticated and authorised users only
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1465590 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java/broker-plugins/management-http/src/main')
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java22
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java32
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementUtil.java225
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/ForbiddingAuthorisationFilter.java73
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/RedirectingAuthorisationFilter.java83
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java239
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java3
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogoutServlet.java4
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java36
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/index.html2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/checkUser.js78
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js161
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/login.html120
13 files changed, 719 insertions, 359 deletions
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
index 5f281504e9..2f51e30b57 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
@@ -24,6 +24,7 @@ import java.io.File;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -33,9 +34,10 @@ import org.apache.log4j.Logger;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
+import org.apache.qpid.server.management.plugin.filter.ForbiddingAuthorisationFilter;
+import org.apache.qpid.server.management.plugin.filter.RedirectingAuthorisationFilter;
import org.apache.qpid.server.management.plugin.servlet.DefinedFileServlet;
import org.apache.qpid.server.management.plugin.servlet.FileServlet;
-import org.apache.qpid.server.management.plugin.servlet.rest.AbstractServlet;
import org.apache.qpid.server.management.plugin.servlet.rest.HelperServlet;
import org.apache.qpid.server.management.plugin.servlet.rest.LogRecordsServlet;
import org.apache.qpid.server.management.plugin.servlet.rest.LogoutServlet;
@@ -66,15 +68,17 @@ import org.apache.qpid.server.model.adapter.AbstractPluginAdapter;
import org.apache.qpid.server.plugin.PluginFactory;
import org.apache.qpid.server.util.MapValueConverter;
import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.DispatcherType;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
+import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
-public class HttpManagement extends AbstractPluginAdapter
+public class HttpManagement extends AbstractPluginAdapter implements HttpManagementConfiguration
{
private final Logger _logger = Logger.getLogger(HttpManagement.class);
@@ -105,8 +109,6 @@ public class HttpManagement extends AbstractPluginAdapter
add(PluginFactory.PLUGIN_TYPE);
}});
- public static final String ENTRY_POINT_PATH = "/management";
-
private static final String OPERATIONAL_LOGGING_NAME = "Web";
@@ -266,8 +268,14 @@ public class HttpManagement extends AbstractPluginAdapter
server.setHandler(root);
// set servlet context attributes for broker and configuration
- root.getServletContext().setAttribute(AbstractServlet.ATTR_BROKER, _broker);
- root.getServletContext().setAttribute(AbstractServlet.ATTR_MANAGEMENT, this);
+ root.getServletContext().setAttribute(HttpManagementUtil.ATTR_BROKER, _broker);
+ root.getServletContext().setAttribute(HttpManagementUtil.ATTR_MANAGEMENT_CONFIGURATION, this);
+
+ FilterHolder restAuthorizationFilter = new FilterHolder(new ForbiddingAuthorisationFilter());
+ restAuthorizationFilter.setInitParameter(ForbiddingAuthorisationFilter.INIT_PARAM_ALLOWED, "/rest/sasl");
+ root.addFilter(restAuthorizationFilter, "/rest/*", EnumSet.of(DispatcherType.REQUEST));
+ root.addFilter(new FilterHolder(new RedirectingAuthorisationFilter()), HttpManagementUtil.ENTRY_POINT_PATH, EnumSet.of(DispatcherType.REQUEST));
+ root.addFilter(new FilterHolder(new RedirectingAuthorisationFilter()), "/index.html", EnumSet.of(DispatcherType.REQUEST));
addRestServlet(root, "broker");
addRestServlet(root, "virtualhost", VirtualHost.class);
@@ -291,7 +299,7 @@ public class HttpManagement extends AbstractPluginAdapter
root.addServlet(new ServletHolder(new SaslServlet()), "/rest/sasl");
- root.addServlet(new ServletHolder(new DefinedFileServlet("index.html")), ENTRY_POINT_PATH);
+ root.addServlet(new ServletHolder(new DefinedFileServlet("index.html")), HttpManagementUtil.ENTRY_POINT_PATH);
root.addServlet(new ServletHolder(new LogoutServlet()), "/logout");
root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.js");
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java
new file mode 100644
index 0000000000..104fe42f46
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java
@@ -0,0 +1,32 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.qpid.server.management.plugin;
+
+public interface HttpManagementConfiguration
+{
+ boolean isHttpsSaslAuthenticationEnabled();
+
+ boolean isHttpSaslAuthenticationEnabled();
+
+ boolean isHttpsBasicAuthenticationEnabled();
+
+ boolean isHttpBasicAuthenticationEnabled();
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementUtil.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementUtil.java
new file mode 100644
index 0000000000..68ec9f532c
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementUtil.java
@@ -0,0 +1,225 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.qpid.server.management.plugin;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.security.AccessControlException;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+import javax.security.auth.Subject;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.HttpManagementActor;
+import org.apache.qpid.server.management.plugin.session.LoginLogoutReporter;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
+
+public class HttpManagementUtil
+{
+
+ /**
+ * Servlet context attribute holding a reference to a broker instance
+ */
+ public static final String ATTR_BROKER = "Qpid.broker";
+
+ /**
+ * Servlet context attribute holding a reference to plugin configuration
+ */
+ public static final String ATTR_MANAGEMENT_CONFIGURATION = "Qpid.managementConfiguration";
+
+ /**
+ * Default management entry URL
+ */
+ public static final String ENTRY_POINT_PATH = "/management";
+
+ private static final String ATTR_LOGIN_LOGOUT_REPORTER = "Qpid.loginLogoutReporter";
+ private static final String ATTR_SUBJECT = "Qpid.subject";
+ private static final String ATTR_LOG_ACTOR = "Qpid.logActor";
+
+ public static Broker getBroker(ServletContext servletContext)
+ {
+ return (Broker) servletContext.getAttribute(ATTR_BROKER);
+ }
+
+ public static HttpManagementConfiguration getManagementConfiguration(ServletContext servletContext)
+ {
+ return (HttpManagementConfiguration) servletContext.getAttribute(ATTR_MANAGEMENT_CONFIGURATION);
+ }
+
+ public static SocketAddress getSocketAddress(HttpServletRequest request)
+ {
+ return InetSocketAddress.createUnresolved(request.getServerName(), request.getServerPort());
+ }
+
+ public static Subject getAuthorisedSubject(HttpSession session)
+ {
+ return (Subject) session.getAttribute(ATTR_SUBJECT);
+ }
+
+ public static void checkRequestAuthenticatedAndAccessAuthorized(HttpServletRequest request, Broker broker,
+ HttpManagementConfiguration management)
+ {
+ HttpSession session = request.getSession();
+ Subject subject = getAuthorisedSubject(session);
+ if (subject == null)
+ {
+ subject = tryToAuthenticate(request, broker, management);
+ if (subject == null)
+ {
+ throw new SecurityException("Only authenticated users can access the management interface");
+ }
+ LogActor actor = createHttpManagementActor(broker, request);
+ if (hasAccessToManagement(broker.getSecurityManager(), subject, actor))
+ {
+ saveAuthorisedSubject(session, subject, actor);
+ }
+ else
+ {
+ throw new AccessControlException("Access to the management interface denied");
+ }
+ }
+ }
+
+ public static boolean hasAccessToManagement(final SecurityManager securityManager, Subject subject, LogActor actor)
+ {
+ // TODO: We should eliminate SecurityManager.setThreadSubject in favour of Subject.doAs
+ SecurityManager.setThreadSubject(subject); // Required for accessManagement check
+ CurrentActor.set(actor);
+ try
+ {
+ try
+ {
+ return Subject.doAs(subject, new PrivilegedExceptionAction<Boolean>()
+ {
+ @Override
+ public Boolean run() throws Exception
+ {
+ return securityManager.accessManagement();
+ }
+ });
+ }
+ catch (PrivilegedActionException e)
+ {
+ throw new RuntimeException("Unable to perform access check", e);
+ }
+ }
+ finally
+ {
+ try
+ {
+ CurrentActor.remove();
+ }
+ finally
+ {
+ SecurityManager.setThreadSubject(null);
+ }
+ }
+ }
+
+ public static HttpManagementActor getOrCreateAndCacheLogActor(HttpServletRequest request, Broker broker)
+ {
+ HttpSession session = request.getSession();
+ HttpManagementActor actor = (HttpManagementActor) session.getAttribute(ATTR_LOG_ACTOR);
+ if (actor == null)
+ {
+ actor = createHttpManagementActor(broker, request);
+ session.setAttribute(ATTR_LOG_ACTOR, actor);
+ }
+ return actor;
+ }
+
+ public static void saveAuthorisedSubject(HttpSession session, Subject subject, LogActor logActor)
+ {
+ session.setAttribute(ATTR_SUBJECT, subject);
+
+ // Cause the user logon to be logged.
+ session.setAttribute(ATTR_LOGIN_LOGOUT_REPORTER, new LoginLogoutReporter(logActor, subject));
+ }
+
+ private static Subject tryToAuthenticate(HttpServletRequest request, Broker broker, HttpManagementConfiguration management)
+ {
+ Subject subject = null;
+ SocketAddress localAddress = getSocketAddress(request);
+ SubjectCreator subjectCreator = broker.getSubjectCreator(localAddress);
+ String remoteUser = request.getRemoteUser();
+
+ if (remoteUser != null || subjectCreator.isAnonymousAuthenticationAllowed())
+ {
+ subject = authenticateUser(subjectCreator, remoteUser, null);
+ }
+ else
+ {
+ String header = request.getHeader("Authorization");
+ if (header != null)
+ {
+ String[] tokens = header.split("\\s");
+ if (tokens.length >= 2 && "BASIC".equalsIgnoreCase(tokens[0]))
+ {
+ boolean isBasicAuthSupported = false;
+ if (request.isSecure())
+ {
+ isBasicAuthSupported = management.isHttpsBasicAuthenticationEnabled();
+ }
+ else
+ {
+ isBasicAuthSupported = management.isHttpBasicAuthenticationEnabled();
+ }
+ if (isBasicAuthSupported)
+ {
+ String base64UsernameAndPassword = tokens[1];
+ String[] credentials = (new String(Base64.decodeBase64(base64UsernameAndPassword.getBytes()))).split(":", 2);
+ if (credentials.length == 2)
+ {
+ subject = authenticateUser(subjectCreator, credentials[0], credentials[1]);
+ }
+ }
+ }
+ }
+ }
+ return subject;
+ }
+
+ private static Subject authenticateUser(SubjectCreator subjectCreator, String username, String password)
+ {
+ SubjectAuthenticationResult authResult = subjectCreator.authenticate(username, password);
+ if (authResult.getStatus() == AuthenticationStatus.SUCCESS)
+ {
+ return authResult.getSubject();
+ }
+ return null;
+ }
+
+ private static HttpManagementActor createHttpManagementActor(Broker broker, HttpServletRequest request)
+ {
+ return new HttpManagementActor(broker.getRootMessageLogger(), request.getRemoteAddr(), request.getRemotePort());
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/ForbiddingAuthorisationFilter.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/ForbiddingAuthorisationFilter.java
new file mode 100644
index 0000000000..b7f4b347c7
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/ForbiddingAuthorisationFilter.java
@@ -0,0 +1,73 @@
+package org.apache.qpid.server.management.plugin.filter;
+
+import java.io.IOException;
+import java.security.AccessControlException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.management.plugin.HttpManagementConfiguration;
+import org.apache.qpid.server.management.plugin.HttpManagementUtil;
+import org.apache.qpid.server.model.Broker;
+
+public class ForbiddingAuthorisationFilter implements Filter
+{
+ public static String INIT_PARAM_ALLOWED = "allowed";
+ private String _allowed = null;
+
+ private Broker _broker;
+ private HttpManagementConfiguration _managementConfiguration;
+
+ @Override
+ public void destroy()
+ {
+ }
+
+ @Override
+ public void init(FilterConfig config) throws ServletException
+ {
+ String allowed = config.getInitParameter(INIT_PARAM_ALLOWED);
+ if (allowed != null)
+ {
+ _allowed = allowed;
+ }
+ ServletContext servletContext = config.getServletContext();
+ _broker = HttpManagementUtil.getBroker(servletContext);
+ _managementConfiguration = HttpManagementUtil.getManagementConfiguration(servletContext);
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
+ ServletException
+ {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+ String servletPath = httpRequest.getServletPath();
+ if (_allowed == null || "".equals(_allowed) || servletPath.indexOf(_allowed) == -1)
+ {
+ try
+ {
+ HttpManagementUtil.checkRequestAuthenticatedAndAccessAuthorized(httpRequest, _broker, _managementConfiguration);
+ }
+ catch(AccessControlException e)
+ {
+ httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ catch(SecurityException e)
+ {
+ httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ return;
+ }
+ }
+ chain.doFilter(request, response);
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/RedirectingAuthorisationFilter.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/RedirectingAuthorisationFilter.java
new file mode 100644
index 0000000000..c5e9890620
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/filter/RedirectingAuthorisationFilter.java
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.qpid.server.management.plugin.filter;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.management.plugin.HttpManagementConfiguration;
+import org.apache.qpid.server.management.plugin.HttpManagementUtil;
+import org.apache.qpid.server.model.Broker;
+
+public class RedirectingAuthorisationFilter implements Filter
+{
+ public static String DEFAULT_LOGIN_URL = "login.html";
+ public static String INIT_PARAM_LOGIN_URL = "login-url";
+
+ private String _loginUrl = DEFAULT_LOGIN_URL;
+ private Broker _broker;
+ private HttpManagementConfiguration _managementConfiguration;
+
+ @Override
+ public void destroy()
+ {
+ }
+
+ @Override
+ public void init(FilterConfig config) throws ServletException
+ {
+ String loginlUrl = config.getInitParameter(INIT_PARAM_LOGIN_URL);
+ if (loginlUrl != null)
+ {
+ _loginUrl = loginlUrl;
+ }
+ ServletContext servletContext = config.getServletContext();
+ _broker = HttpManagementUtil.getBroker(servletContext);
+ _managementConfiguration = HttpManagementUtil.getManagementConfiguration(servletContext);
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
+ ServletException
+ {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+ try
+ {
+ HttpManagementUtil.checkRequestAuthenticatedAndAccessAuthorized(httpRequest, _broker, _managementConfiguration);
+ chain.doFilter(request, response);
+ }
+ catch(SecurityException e)
+ {
+ httpResponse.sendRedirect(_loginUrl);
+ }
+ }
+
+}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
index 689bdb50d8..9614ded3d8 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
@@ -21,9 +21,6 @@
package org.apache.qpid.server.management.plugin.servlet.rest;
import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.security.AccessControlException;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
@@ -34,44 +31,22 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.logging.LogActor;
-import org.apache.qpid.server.logging.RootMessageLogger;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.actors.HttpManagementActor;
-import org.apache.qpid.server.management.plugin.HttpManagement;
-import org.apache.qpid.server.management.plugin.session.LoginLogoutReporter;
+import org.apache.qpid.server.management.plugin.HttpManagementConfiguration;
+import org.apache.qpid.server.management.plugin.HttpManagementUtil;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.security.SecurityManager;
-import org.apache.qpid.server.security.SubjectCreator;
-import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
-import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
-import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
public abstract class AbstractServlet extends HttpServlet
{
private static final Logger LOGGER = Logger.getLogger(AbstractServlet.class);
- /**
- * Servlet context attribute holding a reference to a broker instance
- */
- public static final String ATTR_BROKER = "Qpid.broker";
-
- /**
- * Servlet context attribute holding a reference to plugin configuration
- */
- public static final String ATTR_MANAGEMENT = "Qpid.management";
-
- private static final String ATTR_LOGIN_LOGOUT_REPORTER = "AbstractServlet.loginLogoutReporter";
- private static final String ATTR_SUBJECT = "AbstractServlet.subject";
- private static final String ATTR_LOG_ACTOR = "AbstractServlet.logActor";
-
private Broker _broker;
- private RootMessageLogger _rootLogger;
- private HttpManagement _httpManagement;
+ private HttpManagementConfiguration _managementConfiguration;
protected AbstractServlet()
{
@@ -83,9 +58,8 @@ public abstract class AbstractServlet extends HttpServlet
{
ServletConfig servletConfig = getServletConfig();
ServletContext servletContext = servletConfig.getServletContext();
- _broker = (Broker)servletContext.getAttribute(ATTR_BROKER);
- _rootLogger = _broker.getRootMessageLogger();
- _httpManagement = (HttpManagement)servletContext.getAttribute(ATTR_MANAGEMENT);
+ _broker = HttpManagementUtil.getBroker(servletContext);
+ _managementConfiguration = HttpManagementUtil.getManagementConfiguration(servletContext);
super.init();
}
@@ -211,18 +185,18 @@ public abstract class AbstractServlet extends HttpServlet
Subject subject;
try
{
- subject = getAndCacheAuthorizedSubject(request);
+ subject = getAuthorisedSubject(request);
}
- catch (AccessControlException e)
+ catch (SecurityException e)
{
- sendError(resp, HttpServletResponse.SC_FORBIDDEN);
+ sendError(resp, HttpServletResponse.SC_UNAUTHORIZED);
return;
}
SecurityManager.setThreadSubject(subject);
try
{
- HttpManagementActor logActor = getLogActorAndCacheInSession(request);
+ HttpManagementActor logActor = HttpManagementUtil.getOrCreateAndCacheLogActor(request, _broker);
CurrentActor.set(logActor);
try
{
@@ -256,187 +230,24 @@ public abstract class AbstractServlet extends HttpServlet
}
}
- /**
- * Gets the logged-in {@link Subject} by trying the following:
- *
- * <ul>
- * <li>Get it from the session</li>
- * <li>Get it from the request</li>
- * <li>Log in using the username and password in the Authorization HTTP header</li>
- * <li>Create a Subject representing the anonymous user.</li>
- * </ul>
- *
- * If an authenticated subject is found it is cached in the http session.
- */
- private Subject getAndCacheAuthorizedSubject(HttpServletRequest request)
+ protected Subject getAuthorisedSubject(HttpServletRequest request)
{
- HttpSession session = request.getSession();
- Subject subject = getAuthorisedSubjectFromSession(session);
-
- if(subject != null)
- {
- return subject;
- }
-
- SubjectCreator subjectCreator = getSubjectCreator(request);
- subject = authenticate(request, subjectCreator);
- if (subject != null)
+ Subject subject = HttpManagementUtil.getAuthorisedSubject(request.getSession());
+ if (subject == null)
{
- authoriseManagement(request, subject);
- setAuthorisedSubjectInSession(subject, request, session);
+ throw new SecurityException("Access to management rest interfaces is denied for un-authorised user");
}
- else
- {
- subject = subjectCreator.createSubjectWithGroups(AnonymousAuthenticationManager.ANONYMOUS_USERNAME);
- }
-
return subject;
}
- protected void authoriseManagement(HttpServletRequest request, Subject subject)
- {
- // TODO: We should eliminate SecurityManager.setThreadSubject in favour of Subject.doAs
- SecurityManager.setThreadSubject(subject); // Required for accessManagement check
- LogActor actor = createHttpManagementActor(request);
- CurrentActor.set(actor);
- try
- {
- try
- {
- Subject.doAs(subject, new PrivilegedExceptionAction<Void>() // Required for proper logging of Subject
- {
- @Override
- public Void run() throws Exception
- {
- boolean allowed = getSecurityManager().accessManagement();
- if (!allowed)
- {
- throw new AccessControlException("User is not authorised for management");
- }
- return null;
- }
- });
- }
- catch (PrivilegedActionException e)
- {
- throw new RuntimeException("Unable to perform access check", e);
- }
- }
- finally
- {
- try
- {
- CurrentActor.remove();
- }
- finally
- {
- SecurityManager.setThreadSubject(null);
- }
- }
- }
-
- private Subject authenticate(HttpServletRequest request, SubjectCreator subjectCreator)
- {
- Subject subject = null;
-
- String remoteUser = request.getRemoteUser();
- if(remoteUser != null)
- {
- subject = authenticateUserAndGetSubject(subjectCreator, remoteUser, null);
- }
- else
- {
- String header = request.getHeader("Authorization");
-
- if (header != null)
- {
- String[] tokens = header.split("\\s");
- if(tokens.length >= 2 && "BASIC".equalsIgnoreCase(tokens[0]))
- {
- if(!isBasicAuthSupported(request))
- {
- //TODO: write a return response indicating failure?
- throw new IllegalArgumentException("BASIC Authorization is not enabled.");
- }
-
- subject = performBasicAuth(subject, subjectCreator, tokens[1]);
- }
- }
- }
-
- return subject;
- }
-
- private Subject performBasicAuth(Subject subject,SubjectCreator subjectCreator, String base64UsernameAndPassword)
- {
- String[] credentials = (new String(Base64.decodeBase64(base64UsernameAndPassword.getBytes()))).split(":",2);
- if(credentials.length == 2)
- {
- subject = authenticateUserAndGetSubject(subjectCreator, credentials[0], credentials[1]);
- }
- else
- {
- //TODO: write a return response indicating failure?
- throw new AccessControlException("Invalid number of credentials supplied: "
- + credentials.length);
- }
- return subject;
- }
-
- private Subject authenticateUserAndGetSubject(SubjectCreator subjectCreator, String username, String password)
- {
- SubjectAuthenticationResult authResult = subjectCreator.authenticate(username, password);
- if( authResult.getStatus() != AuthenticationStatus.SUCCESS)
- {
- //TODO: write a return response indicating failure?
- throw new AccessControlException("Incorrect username or password");
- }
- Subject subject = authResult.getSubject();
- return subject;
- }
-
- private boolean isBasicAuthSupported(HttpServletRequest req)
- {
- return req.isSecure() ? _httpManagement.isHttpsBasicAuthenticationEnabled()
- : _httpManagement.isHttpBasicAuthenticationEnabled();
- }
-
- private HttpManagementActor getLogActorAndCacheInSession(HttpServletRequest req)
- {
- HttpSession session = req.getSession();
-
- HttpManagementActor actor = (HttpManagementActor) session.getAttribute(ATTR_LOG_ACTOR);
- if(actor == null)
- {
- actor = createHttpManagementActor(req);
- session.setAttribute(ATTR_LOG_ACTOR, actor);
- }
-
- return actor;
- }
-
- protected Subject getAuthorisedSubjectFromSession(HttpSession session)
- {
- return (Subject)session.getAttribute(ATTR_SUBJECT);
- }
-
- protected void setAuthorisedSubjectInSession(Subject subject, HttpServletRequest request, final HttpSession session)
- {
- session.setAttribute(ATTR_SUBJECT, subject);
-
- LogActor logActor = createHttpManagementActor(request);
- // Cause the user logon to be logged.
- session.setAttribute(ATTR_LOGIN_LOGOUT_REPORTER, new LoginLogoutReporter(logActor, subject));
- }
-
protected Broker getBroker()
{
return _broker;
}
- protected SocketAddress getSocketAddress(HttpServletRequest request)
+ protected HttpManagementConfiguration getManagementConfiguration()
{
- return InetSocketAddress.createUnresolved(request.getServerName(), request.getServerPort());
+ return _managementConfiguration;
}
protected void sendError(final HttpServletResponse resp, int errorCode)
@@ -450,24 +261,4 @@ public abstract class AbstractServlet extends HttpServlet
throw new RuntimeException("Failed to send error response code " + errorCode, e);
}
}
-
- private HttpManagementActor createHttpManagementActor(HttpServletRequest request)
- {
- return new HttpManagementActor(_rootLogger, request.getRemoteAddr(), request.getRemotePort());
- }
-
- protected HttpManagement getManagement()
- {
- return _httpManagement;
- }
-
- protected SecurityManager getSecurityManager()
- {
- return _broker.getSecurityManager();
- }
-
- protected SubjectCreator getSubjectCreator(HttpServletRequest request)
- {
- return _broker.getSubjectCreator(getSocketAddress(request));
- }
}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java
index 3c6fb1c44d..a77096fbe8 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java
@@ -33,7 +33,6 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.qpid.server.management.plugin.servlet.rest.action.ListAuthenticationProviderAttributes;
import org.apache.qpid.server.management.plugin.servlet.rest.action.ListMessageStoreTypes;
-import org.apache.qpid.server.model.Broker;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
@@ -96,7 +95,7 @@ public class HelperServlet extends AbstractServlet
}
}
- Object output = action.perform(parameters, (Broker) getServletContext().getAttribute(ATTR_BROKER));
+ Object output = action.perform(parameters, getBroker());
if (output == null)
{
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogoutServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogoutServlet.java
index 4188e7d60d..34b115ed13 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogoutServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogoutServlet.java
@@ -29,13 +29,13 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
-import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.management.plugin.HttpManagementUtil;
@SuppressWarnings("serial")
public class LogoutServlet extends HttpServlet
{
public static final String RETURN_URL_INIT_PARAM = "qpid.webui_logout_redirect";
- private String _returnUrl = HttpManagement.ENTRY_POINT_PATH;
+ private String _returnUrl = HttpManagementUtil.ENTRY_POINT_PATH;
@Override
public void init(ServletConfig config) throws ServletException
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
index 069132af1e..3053d36c61 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
@@ -25,7 +25,10 @@ import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.apache.log4j.Logger;
-import org.apache.qpid.server.management.plugin.HttpManagement;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.management.plugin.HttpManagementConfiguration;
+import org.apache.qpid.server.management.plugin.HttpManagementUtil;
+import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
@@ -38,7 +41,6 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
-import java.security.AccessControlException;
import java.security.Principal;
import java.security.SecureRandom;
import java.util.LinkedHashMap;
@@ -80,7 +82,7 @@ public class SaslServlet extends AbstractServlet
String[] mechanisms = subjectCreator.getMechanisms().split(" ");
Map<String, Object> outputObject = new LinkedHashMap<String, Object>();
- final Subject subject = getAuthorisedSubjectFromSession(session);
+ final Subject subject = getAuthorisedSubject(request);
if(subject != null)
{
Principal principal = AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(subject);
@@ -195,8 +197,8 @@ public class SaslServlet extends AbstractServlet
private void checkSaslAuthEnabled(HttpServletRequest request)
{
- boolean saslAuthEnabled;
- HttpManagement management = getManagement();
+ boolean saslAuthEnabled = false;
+ HttpManagementConfiguration management = getManagementConfiguration();
if (request.isSecure())
{
saslAuthEnabled = management.isHttpsSaslAuthenticationEnabled();
@@ -205,7 +207,6 @@ public class SaslServlet extends AbstractServlet
{
saslAuthEnabled = management.isHttpSaslAuthenticationEnabled();
}
-
if (!saslAuthEnabled)
{
throw new RuntimeException("Sasl authentication disabled.");
@@ -227,7 +228,7 @@ public class SaslServlet extends AbstractServlet
session.removeAttribute(ATTR_ID);
session.removeAttribute(ATTR_SASL_SERVER);
session.removeAttribute(ATTR_EXPIRY);
- response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
@@ -236,17 +237,15 @@ public class SaslServlet extends AbstractServlet
{
Subject subject = subjectCreator.createSubjectWithGroups(saslServer.getAuthorizationID());
- try
- {
- authoriseManagement(request, subject);
- }
- catch (AccessControlException ace)
+ Broker broker = getBroker();
+ LogActor actor = HttpManagementUtil.getOrCreateAndCacheLogActor(request, broker);
+ if (!HttpManagementUtil.hasAccessToManagement(broker.getSecurityManager(), subject, actor))
{
sendError(response, HttpServletResponse.SC_FORBIDDEN);
return;
}
- setAuthorisedSubjectInSession(subject, request, session);
+ HttpManagementUtil.saveAuthorisedSubject(request.getSession(), subject, actor);
session.removeAttribute(ATTR_ID);
session.removeAttribute(ATTR_SASL_SERVER);
session.removeAttribute(ATTR_EXPIRY);
@@ -274,4 +273,15 @@ public class SaslServlet extends AbstractServlet
mapper.writeValue(writer, outputObject);
}
}
+
+ private SubjectCreator getSubjectCreator(HttpServletRequest request)
+ {
+ return getBroker().getSubjectCreator(HttpManagementUtil.getSocketAddress(request));
+ }
+
+ @Override
+ protected Subject getAuthorisedSubject(HttpServletRequest request)
+ {
+ return HttpManagementUtil.getAuthorisedSubject(request.getSession());
+ }
}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
index 2fb9137ff8..a9cb580103 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
@@ -65,7 +65,7 @@
"qpid/management/treeView",
"qpid/management/controller",
"qpid/common/footer",
- "qpid/authorization/sasl"]);
+ "qpid/authorization/checkUser"]);
</script>
</head>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/checkUser.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/checkUser.js
new file mode 100644
index 0000000000..6b843d8d06
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/checkUser.js
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+ */
+
+require(["dijit/form/DropDownButton",
+ "dijit/TooltipDialog",
+ "dijit/form/TextBox",
+ "dojo/_base/xhr",
+ "dojo/dom",
+ "dojo/dom-construct",
+ "qpid/authorization/sasl",
+ "dojo/domReady!"], function(DropDownButton, TooltipDialog, TextBox, xhr, dom, domConstruct, sasl){
+
+var dialog = new TooltipDialog({
+ content:
+ '<strong><label for="username" style="display:inline-block;width:100px;">Username:</label></strong>' +
+ '<div data-dojo-type="dijit.form.TextBox" id="username"></div><br/>' +
+ '<strong><label for="pass" style="display:inline-block;width:100px;">Password:</label></strong>' +
+ '<div data-dojo-type="dijit.form.TextBox" type="password" id="pass"></div><br/>' +
+ '<button data-dojo-type="dijit.form.Button" type="submit" id="loginButton">Login</button>'
+});
+
+var button = new DropDownButton({
+ label: "Login",
+ dropDown: dialog
+});
+
+var usernameSpan = domConstruct.create("span", {
+ innerHTML: '<strong>User: </strong> <span id="authenticatedUser"></span><a href="logout">[logout]</a>',
+ style: { display: "none" }
+});
+
+
+var loginDiv = dom.byId("login");
+loginDiv.appendChild(usernameSpan);
+loginDiv.appendChild(button.domNode);
+
+var updateUI = function updateUI(data)
+{
+ if(data.user)
+ {
+ dojo.byId("authenticatedUser").innerHTML = data.user;
+ dojo.style(button.domNode, {display: 'none'});
+ dojo.style(usernameSpan, {display: 'block'});
+ }
+ else
+ {
+ dojo.style(button.domNode, {display: 'block'});
+ dojo.style(usernameSpan, {display: 'none'});
+ }
+};
+
+dijit.byId("loginButton").on("click", function(){
+ sasl.authenticate(dojo.byId("username").value, dojo.byId("pass").value, updateUI);
+});
+
+dialog.startup();
+
+sasl.getUser(updateUI);
+
+}); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js
index b4f0728685..33e736322f 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js
@@ -18,10 +18,7 @@
* under the License.
*
*/
-require(["dijit/form/DropDownButton", "dijit/TooltipDialog", "dijit/form/TextBox",
- "dojo/_base/xhr", "dojox/encoding/base64", "dojox/encoding/digests/_base", "dojox/encoding/digests/MD5"]);
-var button;
-var usernameSpan;
+define(["dojo/_base/xhr", "dojox/encoding/base64", "dojox/encoding/digests/_base", "dojox/encoding/digests/MD5"], function () {
var encodeUTF8 = function encodeUTF8(str) {
var byteArray = [];
@@ -49,8 +46,23 @@ var decodeUTF8 = function decodeUTF8(byteArray)
return decodeURIComponent(str);
};
+var errorHandler = function errorHandler(error)
+{
+ if(error.status == 401)
+ {
+ alert("Authentication Failed");
+ }
+ else if(error.status == 403)
+ {
+ alert("Authorization Failed");
+ }
+ else
+ {
+ alert(error);
+ }
+}
-var saslPlain = function saslPlain(user, password)
+var saslPlain = function saslPlain(user, password, callbackFunction)
{
var responseArray = [ 0 ].concat(encodeUTF8( user )).concat( [ 0 ] ).concat( encodeUTF8( password ) );
var plainResponse = dojox.encoding.base64.encode(responseArray);
@@ -65,25 +77,10 @@ var saslPlain = function saslPlain(user, password)
},
handleAs: "json",
failOk: true
- }).then(function()
- {
- updateAuthentication();
- },
- function(error)
- {
- if(error.status == 403)
- {
- alert("Authentication Failed");
- }
- else
- {
- alert(error);
- }
- updateAuthentication();
- });
+ }).then(callbackFunction, errorHandler);
};
-var saslCramMD5 = function saslCramMD5(user, password)
+var saslCramMD5 = function saslCramMD5(user, password, saslMechanism, callbackFunction)
{
// Using dojo.xhrGet, as very little information is being sent
@@ -91,7 +88,7 @@ var saslCramMD5 = function saslCramMD5(user, password)
// The URL of the request
url: "rest/sasl",
content: {
- mechanism: "CRAM-MD5"
+ mechanism: saslMechanism
},
handleAs: "json",
failOk: true
@@ -121,22 +118,7 @@ var saslCramMD5 = function saslCramMD5(user, password)
},
handleAs: "json",
failOk: true
- }).then(function()
- {
- updateAuthentication();
- },
- function(error)
- {
- if(error.status == 403)
- {
- alert("Authentication Failed");
- }
- else
- {
- alert(error);
- }
- updateAuthentication();
- });
+ }).then(callbackFunction, errorHandler);
},
function(error)
@@ -163,86 +145,45 @@ var containsMechanism = function containsMechanism(mechanisms, mech)
return false;
};
-var doAuthenticate = function doAuthenticate()
+var SaslClient = {};
+
+SaslClient.authenticate = function(username, password, callbackFunction)
{
dojo.xhrGet({
- // The URL of the request
url: "rest/sasl",
- handleAs: "json"
+ handleAs: "json",
+ failOk: true
}).then(function(data)
{
- var mechMap = data.mechanisms;
-
- if (containsMechanism(mechMap, "CRAM-MD5"))
- {
- saslCramMD5(dojo.byId("username").value, dojo.byId("pass").value);
- updateAuthentication();
- }
- else if (containsMechanism(mechMap, "PLAIN"))
- {
- saslPlain(dojo.byId("username").value, dojo.byId("pass").value);
- updateAuthentication();
- }
- else
- {
- alert("No supported SASL mechanism offered: " + mechMap);
- }
- }
- );
-
-
+ var mechMap = data.mechanisms;
+ if (containsMechanism(mechMap, "CRAM-MD5"))
+ {
+ saslCramMD5(username, password, "CRAM-MD5", callbackFunction);
+ }
+ else if (containsMechanism(mechMap, "CRAM-MD5-HEX"))
+ {
+ var hashedPassword = dojox.encoding.digests.MD5(password, dojox.encoding.digests.outputTypes.Hex);
+ saslCramMD5(username, hashedPassword, "CRAM-MD5-HEX", callbackFunction);
+ }
+ else if (containsMechanism(mechMap, "PLAIN"))
+ {
+ saslPlain(username, password, callbackFunction);
+ }
+ else
+ {
+ alert("No supported SASL mechanism offered: " + mechMap);
+ }
+ }, errorHandler);
};
-
-var updateAuthentication = function updateAuthentication()
+SaslClient.getUser = function(callbackFunction)
{
dojo.xhrGet({
- // The URL of the request
url: "rest/sasl",
- handleAs: "json"
- }).then(function(data)
- {
- if(data.user)
- {
- dojo.byId("authenticatedUser").innerHTML = data.user;
- dojo.style(button.domNode, {display: 'none'});
- dojo.style(usernameSpan, {display: 'block'});
- }
- else
- {
- dojo.style(button.domNode, {display: 'block'});
- dojo.style(usernameSpan, {display: 'none'});
- }
- }
- );
+ handleAs: "json",
+ failOk: true
+ }).then(callbackFunction, errorHandler);
};
-require(["dijit/form/DropDownButton", "dijit/TooltipDialog", "dijit/form/TextBox", "dojo/_base/xhr", "dojo/dom", "dojo/dom-construct", "dojo/domReady!"],
- function(DropDownButton, TooltipDialog, TextBox, xhr, dom, domConstruct){
- var dialog = new TooltipDialog({
- content:
- '<strong><label for="username" style="display:inline-block;width:100px;">Username:</label></strong>' +
- '<div data-dojo-type="dijit.form.TextBox" id="username"></div><br/>' +
- '<strong><label for="pass" style="display:inline-block;width:100px;">Password:</label></strong>' +
- '<div data-dojo-type="dijit.form.TextBox" type="password" id="pass"></div><br/>' +
- '<button data-dojo-type="dijit.form.Button" data-dojo-props="onClick:doAuthenticate" type="submit">Login</button>'
- });
-
- button = new DropDownButton({
- label: "Login",
- dropDown: dialog
- });
-
- usernameSpan = domConstruct.create("span", { innerHTML: '<strong>User: </strong> <span id="authenticatedUser"></span><a href="logout">[logout]</a>',
- style: { display: "none" }});
-
-
- var loginDiv = dom.byId("login");
- loginDiv.appendChild(usernameSpan);
- loginDiv.appendChild(button.domNode);
-
-
-
-
- updateAuthentication();
-}); \ No newline at end of file
+return SaslClient;
+});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/login.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/login.html
new file mode 100644
index 0000000000..aaa2855bd2
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/login.html
@@ -0,0 +1,120 @@
+<!DOCTYPE HTML>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You 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.
+ -->
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Qpid Management Login</title>
+ <link rel="stylesheet" href="dojo/dojo/resources/dojo.css">
+ <link rel="stylesheet" href="dojo/dijit/themes/claro/claro.css">
+ <link rel="stylesheet" href="css/common.css" media="screen">
+ <script>
+ function getContextPath()
+ {
+ var contextPath = "/";
+ var documentURL = document.URL;
+ var managementPageStart = documentURL.lastIndexOf("/");
+ var firstSlashPos = documentURL.indexOf("/", documentURL.indexOf("//") + 2);
+ if (managementPageStart > firstSlashPos)
+ {
+ contextPath = documentURL.substring(firstSlashPos, managementPageStart);
+ }
+ return contextPath;
+ }
+
+ var dojoConfig = {
+ tlmSiblingOfDojo:false,
+ parseOnLoad:true,
+ async:true,
+ baseUrl: getContextPath(),
+ packages:[
+ { name:"dojo", location:"dojo/dojo" },
+ { name:"dijit", location:"dojo/dijit" },
+ { name:"dojox", location:"dojo/dojox" },
+ { name:"qpid", location:"js/qpid" }
+ ]
+ };
+
+ </script>
+ <script src="dojo/dojo/dojo.js">
+ </script>
+
+ <script>
+ require(["dojo/_base/xhr",
+ "dojo/parser",
+ "dijit/form/Form",
+ "dijit/form/Button",
+ "dijit/form/TextBox",
+ "dijit/form/ValidationTextBox",
+ "dijit/layout/BorderContainer",
+ "dijit/layout/ContentPane",
+ "dijit/TitlePane",
+ "dojox/layout/TableContainer",
+ "dojox/validate/us",
+ "dojox/validate/web",
+ "qpid/common/footer"]);
+ </script>
+
+</head>
+<body class="claro">
+
+<div id="pageLayout" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design: 'headline', gutters: false">
+ <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'top'">
+ <div id="header" class="header" style="float: left; width: 300px"></div>
+ <div id="login" style="float: right"></div>
+ </div>
+ <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'center'">
+ <div style="width:350px; margin-left: auto; margin-right: auto;">
+ <div data-dojo-type="dijit.form.Form" method="POST" id="loginForm">
+ <script type="dojo/on" data-dojo-event="submit" data-dojo-args="e">
+ e.preventDefault()
+ if(this.validate()){
+ require(["qpid/authorization/sasl"], function(sasl){
+ var redirectIfAuthenticated = function redirectIfAuthenticated(){
+ sasl.getUser(function(data){
+ if(data.user){
+ window.location = "index.html";
+ }
+ });
+ };
+
+ sasl.authenticate(dijit.byId("username").value, dijit.byId("password").value, redirectIfAuthenticated);
+ });
+ }
+ return false;
+ </script>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title:'Login', toggleable: false" >
+ <div class="dijitDialogPaneContentArea">
+ <div data-dojo-type="dojox.layout.TableContainer" data-dojo-props="cols:1,labelWidth:'100',showLabels:true,orientation:'horiz',customClass:'formLabel'">
+ <div data-dojo-type="dijit.form.ValidationTextBox" id="username" name="username" data-dojo-props="label:'User name:',required:true, intermediateChanges:true"></div>
+ <div data-dojo-type="dijit.form.ValidationTextBox" type="password" id="password" name="password" data-dojo-props="label:'Password:',required:true, intermediateChanges:true"></div>
+ </div>
+ </div>
+ <div class="dijitDialogPaneActionBar">
+ <button data-dojo-type="dijit.form.Button" type="submit" id="loginButton">Login</button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'bottom'">
+ <div qpid-type="footer"></div>
+ </div>
+</div>
+
+</body>
+</html> \ No newline at end of file