diff options
author | Alex Rudyy <orudyy@apache.org> | 2013-04-08 11:17:41 +0000 |
---|---|---|
committer | Alex Rudyy <orudyy@apache.org> | 2013-04-08 11:17:41 +0000 |
commit | ad56a06e1f1c22a0baccb99c27a64ee9564da83b (patch) | |
tree | f6c77961e2f1fcb28e0b65368b8b7cc5a9e3ba6b /qpid/java/broker-plugins/management-http/src/main | |
parent | d85edbc941559aa85c5a998bbb8894f13baaf81c (diff) | |
download | qpid-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')
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 |