/* * Copyright 2013-2017 Simba Open Source * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.simbasecurity.common.request; import org.simbasecurity.api.service.thrift.RequestData; import org.simbasecurity.api.service.thrift.SSOToken; import org.simbasecurity.common.constants.AuthenticationConstants; import org.simbasecurity.common.util.StringUtil; import org.simbasecurity.common.xpath.UserNameTokenNamespaceContext; import org.w3c.dom.Element; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import java.net.*; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.stream.Collectors; import static org.simbasecurity.common.constants.AuthenticationConstants.LOGIN_TOKEN; import static org.simbasecurity.common.constants.AuthenticationConstants.TARGET_URL; import static org.simbasecurity.common.request.RequestConstants.*; public final class RequestUtil { private static final String HTTPS = "https"; private static final String XPATH_PASSWORD = "./wsse:Security/wsse:UsernameToken/wsse:Password/text()"; private static final String XPATH_USERNAME = "./wsse:Security/wsse:UsernameToken/wsse:Username/text()"; private static final XPath XPATH = XPathFactory.newInstance().newXPath(); static { XPATH.setNamespaceContext(new UserNameTokenNamespaceContext()); } public static final String HOST_SERVER_NAME; private RequestUtil() { } static { String hostName; try { hostName = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException ignored) { hostName = "<UNKNOWN>"; } HOST_SERVER_NAME = hostName; } public static String addParameterToUrl(String targetURL, String parameter, String value) { return buildURL(targetURL, Collections.singletonMap(parameter, value)); } public static String addParametersToUrlAndFilterInternalParameters(String targetURL, Map<String, String> requestParameters) { Map<String, String> parameters = filterInteralParameters(requestParameters); return buildURL(targetURL, parameters); } public static String buildURL(final String url, final String parameterName, final String parameterValue) { return buildURL(url, Collections.singletonMap(parameterName, parameterValue)); } public static String buildURL(final String url, final Map<String, String> parameters) { final StringBuilder stringBuilder = new StringBuilder(url); boolean hasQuestionMark = url.contains("?"); for (final Entry<String, String> entry : parameters.entrySet()) { if (hasQuestionMark) { stringBuilder.append('&'); } else { stringBuilder.append('?'); hasQuestionMark = true; } stringBuilder.append(entry.getKey()).append('=').append(entry.getValue()); } return stringBuilder.toString(); } private static Map<String, String> filterInteralParameters(Map<String, String> requestParameters) { if (requestParameters == null) return Collections.emptyMap(); return requestParameters.entrySet().stream().filter(e -> !isSimbaInternalParameter(e.getKey())).collect(Collectors.toMap(Entry::getKey, Entry::getValue)); } private static boolean isSimbaInternalParameter(String key) { return AuthenticationConstants.SIMBA_INTERNALS_REQUEST_CONSTANTS.contains(key); } public static RequestData createRequestData(HttpServletRequest request, String simbaWebURL) { return createRequestData(request, simbaWebURL, null); } public static RequestData createRequestData(HttpServletRequest request, String simbaWebURL, String simbeEidSuccessUrl) { return new RequestData(retrieveRequestParameters(request), retrieveRequestHeaders(request), resolveProtocol(request), simbaWebURL, getSsoToken(request), retrieveClientIpAddress(request), isLogoutRequest(request), isLoginRequest(request), isSSOTokenMappingKeyProvided(request), isChangePasswordRequest(request), isShowChangePasswordRequest(request), request.getMethod(), HOST_SERVER_NAME, getLoginToken(request), simbeEidSuccessUrl); } public static RequestData createWSSERequestData(final HttpServletRequest request, final Element wsseHeader, final String simbaWebURL) { final Map<String, String> requestParameters = retrieveRequestParameters(request); try { requestParameters.put(AuthenticationConstants.USERNAME, XPATH.evaluate(XPATH_USERNAME, wsseHeader)); requestParameters.put(AuthenticationConstants.PASSWORD, XPATH.evaluate(XPATH_PASSWORD, wsseHeader)); } catch (XPathExpressionException ignore) { } return new RequestData(requestParameters, retrieveRequestHeaders(request), resolveProtocol(request), simbaWebURL, null, retrieveClientIpAddress(request), false, true, false, false, false, request.getMethod(), HOST_SERVER_NAME, getLoginToken(request), null); } private static String resolveProtocol(HttpServletRequest request) { String header = request.getHeader(RequestConstants.HEADER_X_ORIGINAL_SCHEME); String requestURL = request.getRequestURL().toString(); String targetURL = request.getParameter(TARGET_URL); if(targetURL != null){ requestURL = targetURL; } return isNotBlank(header) && header.equals(HTTPS) ? convertToHTTPS(requestURL) : requestURL; } private static String convertToHTTPS(final String url) { try { final String urlWithoutProtocol = StringUtil.substringAfter(url, new URL(url).getProtocol()); return HTTPS + urlWithoutProtocol; } catch (MalformedURLException e) { throw new RuntimeException(e); } } private static String getLoginToken(HttpServletRequest request) { return request.getParameter(LOGIN_TOKEN); } private static boolean isLoginRequest(final HttpServletRequest request) { return SIMBA_LOGIN_ACTION.equals(request.getParameter(SIMBA_ACTION_PARAMETER)) || SIMBA_LOGIN_PATH.equals(request.getPathInfo()); } private static boolean isLogoutRequest(final HttpServletRequest request) { return SIMBA_LOGOUT_ACTION.equals(request.getParameter(SIMBA_ACTION_PARAMETER)); } private static boolean isChangePasswordRequest(final HttpServletRequest request) { return SIMBA_CHANGE_PASSWORD_ACTION.equals(request.getParameter(SIMBA_ACTION_PARAMETER)); } private static boolean isShowChangePasswordRequest(final HttpServletRequest request) { return SIMBA_SHOW_CHANGE_PASSWORD_ACTION.equals(request.getParameter(SIMBA_ACTION_PARAMETER)); } private static boolean isSSOTokenMappingKeyProvided(final HttpServletRequest request) { return isNotBlank(getSSOTokenMappingKey(request)); } private static String getSSOTokenMappingKey(final HttpServletRequest request) { return request.getParameter(SIMBA_SSO_TOKEN); } private static boolean isNotBlank(final String string) { return string != null && string.trim().length() > 0; } @SuppressWarnings("unchecked") private static Map<String, String> retrieveRequestHeaders(final HttpServletRequest request) { final Map<String, String> headers = new HashMap<>(); final Enumeration<String> names = request.getHeaderNames(); while (names.hasMoreElements()) { final String name = names.nextElement(); headers.put(name, request.getHeader(name)); } return headers; } @SuppressWarnings("unchecked") private static Map<String, String> retrieveRequestParameters(final HttpServletRequest request) { final Map<String, String> parameters = new HashMap<>(); final Enumeration<String> names = request.getParameterNames(); while (names.hasMoreElements()) { final String name = names.nextElement(); parameters.put(name, request.getParameter(name)); } return parameters; } /** * First check the cookie, fallback to request header */ public static SSOToken getSsoToken(final HttpServletRequest request) { final Cookie ssoCookie = getSSOCookie(request); if (ssoCookie != null) { return new SSOToken(ssoCookie.getValue()); } if (request.getHeader("simbaSSOToken") != null) { return new SSOToken(request.getHeader("simbaSSOToken")); } return null; } /** * Let is explode if nothing found */ public static SSOToken getSsoTokenThatShouldBePresent(final HttpServletRequest request) { SSOToken token = getSsoToken(request); if (token == null) { throw new IllegalStateException("no SSOToken found"); } return token; } private static Cookie getSSOCookie(final HttpServletRequest request) { final Cookie[] cookies = request.getCookies(); if (cookies != null) { for (final Cookie cookie : cookies) { if (RequestConstants.SIMBA_SSO_TOKEN.equals(cookie.getName())) { return cookie; } } } return null; } public static Cookie getSSOCookieThatShouldBePresent(final HttpServletRequest request) { Cookie ssoCookie = getSSOCookie(request); if (ssoCookie == null) { throw new IllegalStateException("no Cookie found"); } return ssoCookie; } public static String retrieveClientIpAddress(final HttpServletRequest request) { String remoteAddress = request.getRemoteAddr(); try { final InetAddress inetAddress = InetAddress.getByName(remoteAddress); if (inetAddress.isLoopbackAddress()) { remoteAddress = InetAddress.getLocalHost().getHostAddress(); } remoteAddress = translateToIPv6Address(remoteAddress, inetAddress); } catch (UnknownHostException ignored) { } final String xForwardedFor = request.getHeader(HEADER_X_FORWARDED_FOR); if (xForwardedFor != null) { final int idx = xForwardedFor.indexOf(','); if (idx >= 0) { remoteAddress = xForwardedFor.substring(0, idx).trim(); } else { remoteAddress = xForwardedFor.trim(); } } return remoteAddress; } private static String translateToIPv6Address(String remoteAddress, InetAddress inetAddress) throws UnknownHostException { if (!inetAddress.isLoopbackAddress() && !(inetAddress instanceof Inet6Address)) { InetAddress[] addresses = InetAddress.getAllByName(inetAddress.getHostName()); for (InetAddress address : addresses) { if (address instanceof Inet6Address) { return address.getHostAddress(); } } } else if (inetAddress.isLoopbackAddress()) { InetAddress[] addresses = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName()); for (InetAddress address : addresses) { if (address instanceof Inet6Address) { return address.getHostAddress(); } } } return remoteAddress; } }