/** * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * https://opensso.dev.java.net/public/CDDLv1.0.html or * opensso/legal/CDDLv1.0.txt * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at opensso/legal/CDDLv1.0.txt. * If applicable, add the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * $Id: CookieWriterServlet.java,v 1.7 2009/11/03 00:50:34 madan_ranganath Exp $ * */ package com.sun.identity.saml2.idpdiscovery; import com.sun.identity.shared.encode.Base64; import java.io.IOException; import java.security.MessageDigest; import java.util.StringTokenizer; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Cookie; /** * The Writer Service is used by the identity provider. After successful * authentication, the common domain cookie is appended with the query parameter * _saml_idp=entity-ID-of-identity-provider. This parameter is used to redirect * the principal to the Writer Service URL defined for the identity provider. * The URL is configured as the value for the Writer Service URL attribute when * an authentication domain is created. Use the format * http://common-domain-host:port/deployment-uri/saml2writer where * common-domain-host:port refers to the machine on which the Common Domain * Services are installed and deployment-uri tells the web container where to * look for information specific to the application (such as classes or JARs). * The default URI is amcommon. */ public class CookieWriterServlet extends HttpServlet { private static String INTRODUCTION_COOKIE_TYPE = SystemProperties.get( IDPDiscoveryConstants.IDPDISCOVERY_COOKIE_TYPE); private static String INTRODUCTION_URL_SCHEME = SystemProperties.get( IDPDiscoveryConstants.IDPDISCOVERY_URL_SCHEME); private static String INTRODUCTION_COOKIE_DOMAIN = SystemProperties.get( IDPDiscoveryConstants.IDPDISCOVERY_COOKIE_DOMAIN); private String preferred_cookie_name = null; /** * Gets handle to debug. * @param config the ServletConfig object that contains configutation * information for this servlet. * @exception ServletException if an exception occurs that interrupts * the servlet's normal operation. */ public void init(ServletConfig config) throws ServletException { super.init(config); if (CookieUtils.debug.messageEnabled()) { CookieUtils.debug.message("CookieWriterServlet Initializing..."); } } /** * Handles the HTTP GET request. * @param request an HttpServletRequest object that contains the request * the client has made of the servlet. * @param response an HttpServletResponse object that contains the response * the servlet sends to the client. * @exception ServletException if an input or output error is detected when * the servlet handles the GET request * @exception IOException if the request for the GET could not be handled */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGetPost(request, response); } /** * Handles the HTTP POST request. * * @param request an HttpServletRequest object that contains the request * the client has made of the servlet. * @param response an HttpServletResponse object that contains the response * the servlet sends to the client. * @exception ServletException if an input or output error is detected when * the servlet handles the GET request * @exception IOException if the request for the GET could not be handled */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGetPost(request, response); } /** * Description : The QueryString will contain providerid=, * LRURL=URL to redirect to after setting the preferred IDP cookie * * @param request an HttpServletRequest object that contains the request * the client has made of the servlet. * @param response an HttpServletResponse object that contains the response * the servlet sends to the client. * @exception ServletException if an input or output error is detected when * the servlet handles the GET request * @exception IOException if the request for the GET could not be handled */ private void doGetPost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String classMethod = "CookieWriterServlet.doGetPost: "; preferred_cookie_name = CookieUtils.getPreferCookieName( request.getRequestURI()); if (preferred_cookie_name == null) { CookieUtils.debug.error( classMethod + "The request uri is null."); CookieUtils.sendError(request, response, response.SC_INTERNAL_SERVER_ERROR, "nullRequestUri", CookieUtils.bundle.getString("nullRequestUri")); return; } else if (preferred_cookie_name.equals("")) { CookieUtils.debug.error( classMethod + "Cannot match the cookie name from " + "the request uri."); CookieUtils.sendError(request, response, response.SC_INTERNAL_SERVER_ERROR, "invalidRequestUri", CookieUtils.bundle.getString("invalidRequestUri")); return; } if (CookieUtils.debug.messageEnabled()) { CookieUtils.debug.message(classMethod + "Preferred Cookie Name is " + preferred_cookie_name); } try { if (INTRODUCTION_COOKIE_TYPE == null || INTRODUCTION_COOKIE_TYPE.trim().length() <= 0) { if (CookieUtils.debug.messageEnabled()) { CookieUtils.debug.message( classMethod + "Cookie type is null, set to persistent." ); } INTRODUCTION_COOKIE_TYPE = IDPDiscoveryConstants.PERSISTENT_COOKIE; } if (INTRODUCTION_URL_SCHEME == null || INTRODUCTION_URL_SCHEME.trim().length() <= 0) { if (CookieUtils.debug.messageEnabled()) { CookieUtils.debug.message( classMethod + "URL Scheme is null, set to https." ); } INTRODUCTION_URL_SCHEME = IDPDiscoveryConstants.HTTPS; } boolean isValidReturn = false; String returnURL = request.getParameter(IDPDiscoveryConstants.LRURL); if (returnURL == null || returnURL.trim().length() <= 0) { // Redirect URL not specified. Do nothing // Do not throw any error page to user as this operation is done // behind the screens. CookieUtils.debug.error( classMethod + "Redirect URL not specified. " + "Cannot reset Preferred IDP cookie."); isValidReturn = false; } else { isValidReturn = true; } String providerId = request.getParameter( preferred_cookie_name ); if (providerId == null || providerId.trim().length() <= 0) { // Nothing to reset in preferred IDP cookie. Do nothing // Do not throw any error page to user as this operation is // done behind the screens. CookieUtils.debug.error( classMethod + "Provider Id not in request, "+ "Cannot reset preferred idp." ); if (isValidReturn) { response.sendRedirect(returnURL); } else { CookieUtils.sendError(request, response, response.SC_INTERNAL_SERVER_ERROR, "noRedirectionURL", CookieUtils.bundle.getString("noRedirectionURL")); } return; } String cookieValue = CookieUtils.getCookieValueFromReq( request, preferred_cookie_name ); boolean bIsSAML2 = CookieUtils.isSAML2(request); if (cookieValue == null || cookieValue.trim().length() <= 0) { // Preferred IDP Cookie does not exist. // Create a new cookie with this provider id as the only // value if (CookieUtils.debug.messageEnabled()) { CookieUtils.debug.message( classMethod + "Preferred IDP Cookie Not found" ); } cookieValue = Base64.encode( generateSuccinctID(providerId, bIsSAML2) ); } else { cookieValue = resetPreferredIDPCookie( cookieValue, providerId, bIsSAML2 ); } if (CookieUtils.debug.messageEnabled()) { CookieUtils.debug.message( classMethod + "Cookie Type is " + INTRODUCTION_COOKIE_TYPE ); CookieUtils.debug.message( classMethod + "Cookie value is " + cookieValue ); CookieUtils.debug.message( classMethod + "Preferred Cookie Name " + preferred_cookie_name ); } int maxAge; String domain = null; if (!(INTRODUCTION_COOKIE_DOMAIN == null || INTRODUCTION_COOKIE_DOMAIN.length() < 1)) { domain = INTRODUCTION_COOKIE_DOMAIN; } if (INTRODUCTION_COOKIE_TYPE.equalsIgnoreCase( IDPDiscoveryConstants.SESSION_COOKIE)) { maxAge = IDPDiscoveryConstants.SESSION_COOKIE_AGE; } else { maxAge = IDPDiscoveryConstants.PERSISTENT_COOKIE_AGE; } Cookie idpListCookie = CookieUtils.newCookie( preferred_cookie_name, cookieValue, maxAge, "/", domain ); CookieUtils.addCookieToResponse(response,idpListCookie); if(isValidReturn) { if (CookieUtils.debug.messageEnabled()) { CookieUtils.debug.message( classMethod + "Redirect to " + returnURL ); } response.sendRedirect(returnURL); } else { if (CookieUtils.debug.messageEnabled()) { CookieUtils.debug.message( classMethod + "No return URL. " + "Set preferred IDP cookie and "+ "return error page" ); } CookieUtils.sendError(request, response, response.SC_INTERNAL_SERVER_ERROR, "noRedirectionURL", CookieUtils.bundle.getString("noRedirectionURL")); } return; } catch(IOException e) { CookieUtils.debug.error(classMethod, e); } } /** * This function is used to reset the preferred IDP cookie based on the * present value and the providerId of the IDP that calls this service * @param existing cookie value * @param current IDP provider ID that will be added to the top of the list * @return cookie value that needs to be set as the preferred IDP cookie */ private String resetPreferredIDPCookie( String existingCookieValue, String toAddCookieValue, boolean bIsSAML2) { // Steps // 1. Check if existingCookieValue has toAddCookieValue // 2. If yes remove that value from existingCookieValue // 3. append toAddCookieValue to existingCookieValue at end and return StringBuffer returnCookie = new StringBuffer(); String encodedCookieToAdd = Base64.encode( generateSuccinctID(toAddCookieValue, bIsSAML2) ); StringTokenizer st = new StringTokenizer( existingCookieValue, IDPDiscoveryConstants.PREFERRED_COOKIE_SEPERATOR ); while (st.hasMoreTokens()) { String curIdpString = (String)st.nextToken(); if (curIdpString.equals(encodedCookieToAdd)) { continue; } else { returnCookie.append(curIdpString + " "); } } returnCookie.append(encodedCookieToAdd); return returnCookie.toString(); } public byte[] generateSuccinctID(String providerURL, boolean bIsSAML2) { if (providerURL == null || providerURL.length() == 0) { return null; } if (bIsSAML2) { byte[] returnBytes = null; try { returnBytes = providerURL.getBytes("UTF-8"); } catch (Exception e) { CookieUtils.debug.error( "CookieWriterServlet.generateSuccinctID: ", e); returnBytes = null; } return returnBytes; } else { MessageDigest md = null; try { md = MessageDigest.getInstance("SHA"); } catch (Exception e) { CookieUtils.debug.error( "CookieWriterServlet.generateSuccinctID: ", e); return null; } char chars[] = providerURL.toCharArray(); byte bytes[] = new byte[chars.length]; for (int i = 0; i < chars.length; i++) { bytes[i] = (byte) chars[i]; } md.update(bytes); return md.digest(); } } }