/*
* Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.wso2.carbon.ui;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceReference;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.core.common.AuthenticationException;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.ui.deployment.beans.CarbonUIDefinitions;
import org.wso2.carbon.ui.deployment.beans.Context;
import org.wso2.carbon.ui.internal.CarbonUIServiceComponent;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.regex.Matcher;
public class CarbonSecuredHttpContext extends SecuredComponentEntryHttpContext {
public static final String LOGGED_USER = CarbonConstants.LOGGED_USER;
public static final String CARBON_AUTHNETICATOR = "CarbonAuthenticator";
private static final Log log = LogFactory.getLog(CarbonSecuredHttpContext.class);
private Bundle bundle = null;
private HashMap<String, String> httpUrlsToBeByPassed = new HashMap<String, String>();
private HashMap<String, String> urlsToBeByPassed = new HashMap<String, String>();
private String defaultHomePage;
private Context defaultContext;
/**
*
* @param bundle
* @param s
* @param uiResourceRegistry
* @param registry
*/
public CarbonSecuredHttpContext(Bundle bundle, String s, UIResourceRegistry uiResourceRegistry,
Registry registry) {
super(bundle, s, uiResourceRegistry);
this.registry = registry;
this.bundle = bundle;
}
/**
* {@inheritDoc}
*/
public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response)
throws IOException {
String requestedURI = request.getRequestURI();
// Get the matching CarbonUIAuthenticator. If no match found for the given request, this
// will return null.
CarbonUIAuthenticator authenticator = CarbonUILoginUtil.getAuthenticator(request);
// This check is required for Single Logout implementation. If the request is not for SSO
// based authentication page or SSO Servlet, then if the session is invalid redirect the
// requests to logout_action.jsp.
CarbonSSOSessionManager ssoSessionManager = CarbonSSOSessionManager.getInstance();
requestedURI = ssoSessionManager.getRequestedUrl(request,authenticator);
HttpSession session;
String sessionId;
boolean authenticated = false;
try {
// Get the user's current authenticated session - if any exists.
session = request.getSession();
sessionId = session.getId();
Boolean authenticatedObj = (Boolean) session.getAttribute("authenticated");
if (authenticatedObj != null) {
authenticated = authenticatedObj.booleanValue();
if(log.isDebugEnabled()){
log.debug("Is authenticated " + authenticated);
}
}
} catch (Exception e) {
log.debug("No session exits");
return false;
}
String context = request.getContextPath();
if ("/".equals(context)) {
context = "";
}
// We eliminate the /tenant/{tenant-domain} from authentications
Matcher matcher = CarbonUILoginUtil.getTenantEnabledUriPattern().matcher(requestedURI);
if (matcher.matches()) {
log.debug("Tenant webapp request " + requestedURI);
return CarbonUILoginUtil.escapeTenantWebAppRequests(authenticated, response,
requestedURI, context);
}
// TODO: When filtered from a Servlet filter the request uri always contains 2 //, this is a
// temporary fix
if (requestedURI.indexOf("//") == 0) {
requestedURI = requestedURI.substring(1);
}
if (httpUrlsToBeByPassed.isEmpty()) {
// Populates http urls to be by passed.
populatehttpUrlsToBeByPassed();
}
if (requestedURI.equals(context) || requestedURI.equals(context + "/")) {
return handleRequestOnContext(request, response);
}
// Storing intermediate value of requestedURI.
// This is needed for OpenID authentication later.
String tempUrl = requestedURI;
// When war is deployed on top of an existing app server we cannot use root context
// for deployment. Hence a new context is added.Now url changes from eg:
// carbon/admin/index.jsp to wso2/carbon/admin/index.jsp In this case before doing anything,
// we need to remove web app context (eg: wso2) .
CarbonUILoginUtil.addNewContext(requestedURI);
// Disabling http access to admin console user guide documents should be allowed to access
// via http protocol
int val = -1;
if ((val = allowNonSecuredContent(requestedURI, request, response, authenticated,
authenticator)) != CarbonUILoginUtil.CONTINUE) {
if (val == CarbonUILoginUtil.RETURN_TRUE) {
log.debug("Skipping security check for non secured content. " + requestedURI);
return true;
} else {
log.debug("Security check failed for the resource " + requestedURI);
return false;
}
}
// We are allowing requests for .jar/.class resources. Otherwise applets won't get loaded
// due to session checks. (applet loading happens over https://)
if(requestedURI.endsWith(".jar") || requestedURI.endsWith(".class")) {
log.debug("Skipping authentication for .jar files and .class file." + requestedURI);
return true;
}
String resourceURI = requestedURI.replaceFirst("/carbon/", "../");
if (log.isDebugEnabled()) {
log.debug("CarbonSecuredHttpContext -> handleSecurity() requestURI:" + requestedURI
+ " id:" + sessionId + " resourceURI:" + resourceURI);
}
if (urlsToBeByPassed.isEmpty()) {
// retrieve urls that should be by-passed from security check
populateUrlsToBeBypassed();
}
// if the current uri is marked to be by-passed, let it pass through
if (isCurrentUrlToBePassed(request, session, resourceURI)) {
return true;
}
String indexPageURL = CarbonUIUtil.getIndexPageURL(session.getServletContext(),
request.getSession());
// Reading the requestedURL from the cookie to obtain the request made while not
// authanticated; and setting it as the indexPageURL
indexPageURL = CarbonUILoginUtil.getIndexPageUrlFromCookie(requestedURI, indexPageURL,
request);
// If a custom index page is used send the login request with the indexpage specified
indexPageURL = CarbonUILoginUtil.getCustomIndexPage(request, indexPageURL);
// Reading home page set on product.xml
// If the params in the servletcontext is null get them from the UTIL
indexPageURL = updateIndexPageWithHomePage(indexPageURL);
if ((val = CarbonUILoginUtil.handleLoginPageRequest(requestedURI, request, response,
authenticated, context, indexPageURL)) != CarbonUILoginUtil.CONTINUE) {
if (val == CarbonUILoginUtil.RETURN_TRUE) {
return true;
} else {
return false;
}
}
// If authenticator defines to skip URL, return true
if (ssoSessionManager.skipAuthentication(request)) {
if(log.isDebugEnabled()){
log.debug("Skipping security checks for authenticator defined URL " + requestedURI);
}
return true;
}
// If someone signed in from a tenant, try to access a different tenant domain, he should be
// forced to sign out without any prompt Cloud requirement
requestedURI = CarbonUILoginUtil.getForcedSignOutRequestedURI(requestedURI, request);
String contextPath = (request.getContextPath().equals("") || request.getContextPath()
.equals("/")) ? "" : request.getContextPath();
String tenantDomain = (String) session.getAttribute(MultitenantConstants.TENANT_DOMAIN);
if (tenantDomain != null && !tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) {
contextPath += "/" + MultitenantConstants.TENANT_AWARE_URL_PREFIX + "/" + tenantDomain;
}
String httpLogin = request.getParameter("gsHttpRequest");
boolean skipLoginPage = false;
// Login page is not required for all the Authenticators.
if (authenticator != null
&& authenticator.skipLoginPage()
&& requestedURI.indexOf("login_action.jsp") < 0
&& (requestedURI.endsWith("/carbon/") || (requestedURI.indexOf("/registry/atom") == -1 && requestedURI
.endsWith("/carbon")))) {
// Add this to session for future use.
request.getSession().setAttribute("skipLoginPage", "true");
}
if (request.getSession().getAttribute("skipLoginPage") != null) {
if ("true".equals(((String) request.getSession().getAttribute("skipLoginPage")))) {
skipLoginPage = true;
}
}
if (requestedURI.indexOf("login_action.jsp") > -1 && authenticator != null) {
return CarbonUILoginUtil.handleLogin(authenticator, request, response, session,
authenticated, contextPath, indexPageURL, httpLogin);
} else if (requestedURI.indexOf("logout_action.jsp") > 1) {
return CarbonUILoginUtil.handleLogout(authenticator, request, response, session,
authenticated, contextPath, indexPageURL, httpLogin);
}
if (requestedURI.endsWith("/carbon/")) {
if (skipLoginPage) {
response.sendRedirect(contextPath + indexPageURL + "?skipLoginPage=true");
} else {
response.sendRedirect(contextPath + indexPageURL);
}
return false;
} else if (requestedURI.indexOf("/registry/atom") == -1 && requestedURI.endsWith("/carbon")) {
if (skipLoginPage) {
response.sendRedirect(contextPath + indexPageURL + "?skipLoginPage=true");
} else {
response.sendRedirect(contextPath + indexPageURL);
}
return false;
} else if (CarbonUILoginUtil.letRequestedUrlIn(requestedURI, tempUrl)) {
return true;
} else if (requestedURI.endsWith(".jsp") && authenticated) {
return true;
}
if (!authenticated) {
if (requestedURI.endsWith("ajaxprocessor.jsp")) {
// Prevent login page appearing
return true;
} else {
return CarbonUILoginUtil.saveOriginalUrl(authenticator, request, response, session,
skipLoginPage, contextPath, indexPageURL, requestedURI);
}
}
if (request.getSession().isNew()) {
if (skipLoginPage) {
response.sendRedirect(contextPath + "/carbon/admin/login_action.jsp");
} else {
response.sendRedirect(contextPath + "/carbon/admin/login.jsp");
}
return false;
}
return true;
}
/**
*
* @param indexPageURL
* @return
*/
private String updateIndexPageWithHomePage(String indexPageURL) {
// If the params in the servletcontext is null get them from the UTIL
if (defaultHomePage == null) {
defaultHomePage = (String) CarbonUIUtil
.getProductParam(CarbonConstants.PRODUCT_XML_WSO2CARBON
+ CarbonConstants.DEFAULT_HOME_PAGE);
}
if (defaultHomePage != null && defaultHomePage.trim().length() > 0
&& indexPageURL.contains("/carbon/admin/index.jsp")) {
indexPageURL = defaultHomePage;
if (!indexPageURL.startsWith("/")) {
indexPageURL = "/" + indexPageURL;
}
}
return indexPageURL;
}
/**
*
* @param request
* @param session
* @param resourceURI
* @return
*/
private boolean isCurrentUrlToBePassed(HttpServletRequest request, HttpSession session,
String resourceURI) {
if (!urlsToBeByPassed.isEmpty() && urlsToBeByPassed.containsKey(resourceURI)) {
if (log.isDebugEnabled()) {
log.debug("By passing authentication check for URI : " + resourceURI);
}
// Before bypassing, set the backendURL properly so that it doesn't fail
String contextPath = request.getContextPath();
String backendServerURL = request.getParameter("backendURL");
if (backendServerURL == null) {
backendServerURL = CarbonUIUtil.getServerURL(session.getServletContext(),
request.getSession());
}
if ("/".equals(contextPath)) {
contextPath = "";
}
backendServerURL = backendServerURL.replace("${carbon.context}", contextPath);
session.setAttribute(CarbonConstants.SERVER_URL, backendServerURL);
return true;
}
return false;
}
/**
*
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private void populateUrlsToBeBypassed() {
if (bundle != null && urlsToBeByPassed.isEmpty()) {
ServiceReference reference = bundle.getBundleContext().getServiceReference(
CarbonUIDefinitions.class.getName());
CarbonUIDefinitions carbonUIDefinitions;
if (reference != null) {
carbonUIDefinitions = (CarbonUIDefinitions) bundle.getBundleContext().getService(
reference);
if (carbonUIDefinitions != null) {
urlsToBeByPassed = carbonUIDefinitions.getUnauthenticatedUrls();
}
}
}
}
/**
*
* @param requestedURI
* @param request
* @param response
* @param authenticated
* @param authenticator
* @return
* @throws IOException
*/
@SuppressWarnings("deprecation")
private int allowNonSecuredContent(String requestedURI, HttpServletRequest request,
HttpServletResponse response, boolean authenticated, CarbonUIAuthenticator authenticator)
throws IOException {
if (!request.isSecure() && !(requestedURI.endsWith(".html"))) {
// By passing items required for try-it & IDE plugins
if (requestedURI.endsWith(".css") || requestedURI.endsWith(".gif")
|| requestedURI.endsWith(".GIF") || requestedURI.endsWith(".jpg")
|| requestedURI.endsWith(".JPG") || requestedURI.endsWith(".png")
|| requestedURI.endsWith(".PNG") || requestedURI.endsWith(".xsl")
|| requestedURI.endsWith(".xslt") || requestedURI.endsWith(".js")
|| requestedURI.endsWith(".ico") || requestedURI.endsWith("/filedownload")
|| requestedURI.endsWith("/fileupload")
|| requestedURI.contains("/fileupload/")
|| requestedURI.contains("admin/jsp/WSRequestXSSproxy_ajaxprocessor.jsp")
|| requestedURI.contains("registry/atom")
|| requestedURI.contains("registry/tags") || requestedURI.contains("gadgets/")
|| requestedURI.contains("registry/resource")) {
return CarbonUILoginUtil.RETURN_TRUE;
}
String resourceURI = requestedURI.replaceFirst("/carbon/", "../");
// By passing the pages which are specified as bypass https
if (httpUrlsToBeByPassed.containsKey(resourceURI)) {
if (!authenticated) {
try {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(CarbonConstants.REMEMBER_ME_COOKE_NAME)
&& authenticator != null) {
try {
authenticator.authenticateWithCookie(request);
} catch (AuthenticationException ignored) {
// We can ignore here and proceed with normal login.
if (log.isDebugEnabled()) {
log.debug(ignored);
}
}
}
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new IOException(e.getMessage(), e);
}
}
return CarbonUILoginUtil.RETURN_TRUE;
}
String enableHTTPAdminConsole = CarbonUIServiceComponent.getServerConfiguration()
.getFirstProperty(CarbonConstants.ENABLE_HTTP_ADMIN_CONSOLE);
if (enableHTTPAdminConsole == null || "false".equalsIgnoreCase(enableHTTPAdminConsole.trim())) {
String adminConsoleURL = CarbonUIUtil.getAdminConsoleURL(request);
if (adminConsoleURL != null) {
if (log.isTraceEnabled()) {
log.trace("Request came to admin console via http.Forwarding to : "
+ adminConsoleURL);
}
response.sendRedirect(adminConsoleURL);
return CarbonUILoginUtil.RETURN_FALSE;
}
}
}
return CarbonUILoginUtil.CONTINUE;
}
/**
*
* @param request
* @param response
* @return
* @throws IOException
*/
private boolean handleRequestOnContext(HttpServletRequest request, HttpServletResponse response)
throws IOException {
log.debug("Handling request on context");
if (defaultContext != null && !"".equals(defaultContext.getContextName())
&& !"null".equals(defaultContext.getContextName())) {
String adminConsoleURL = CarbonUIUtil.getAdminConsoleURL(request);
int index = adminConsoleURL.lastIndexOf("carbon");
String defaultContextUrl = adminConsoleURL.substring(0, index)
+ defaultContext.getContextName() + "/";
response.sendRedirect(defaultContextUrl);
} else {
response.sendRedirect("carbon");
}
return false;
}
/**
*
*/
@SuppressWarnings("unchecked")
private void populatehttpUrlsToBeByPassed() {
if (bundle != null && httpUrlsToBeByPassed.isEmpty() && defaultContext == null) {
@SuppressWarnings("rawtypes")
ServiceReference reference = bundle.getBundleContext().getServiceReference(
CarbonUIDefinitions.class.getName());
CarbonUIDefinitions carbonUIDefinitions;
if (reference != null) {
carbonUIDefinitions = (CarbonUIDefinitions) bundle.getBundleContext().getService(
reference);
if (carbonUIDefinitions != null) {
httpUrlsToBeByPassed = carbonUIDefinitions.getHttpUrls();
if (carbonUIDefinitions.getContexts().containsKey("default-context")) {
defaultContext = carbonUIDefinitions.getContexts().get("default-context");
}
}
}
}
}
}