libreccm-legacy/ccm-auth-http/src/com/arsdigita/auth/http/HTTPAuthServlet.java

193 lines
5.9 KiB
Java
Executable File

/* -*- mode: java; c-basic-offset: 4; indent-tabs-mode: nil -*-
*
* Copyright (C) 2001 ArsDigita Corporation. All Rights Reserved.
*
* The contents of this file are subject to the ArsDigita Public
* License (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.arsdigita.com/ADPL.txt
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*/
package com.arsdigita.auth.http;
import java.io.IOException;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.ShortBufferException;
import sun.misc.BASE64Encoder;
/**
* <p>
* Attempt to authenticate a user against an IIS server.
* </p>
*
* <p>
* This servlet runs on an IIS server and is used as part of
* the mechanism for automatically authenticating IE users on
* CCM.
* </p>
*
* <p><strong>Managing the public and private keys</strong></p>
*
* <p>
* The IIS server needs to send a signed cookie to the CCM server.
* To do this, the IIS server needs a private key, and the CCM
* server needs the corresponding public key. This section
* describes how to generate and distribute the keys.
* </p>
*
* <p>
* On the IIS server, you need to generate the private/public key
* pair using the Java <code>keytool</code> utility. Run
* <code>keytool</code> like this:
* </p>
*
* <pre>
* keytool -genkey -keyalg rsa -validity 365 -keypass 123456 \
* -dname 'cn=jones' -alias ccmkey
* </pre>
*
* <p>
* The <code>-dname</code> field does not matter. Make sure the
* key store has password <code>123456</code> (or change the
* <code>HTTPAuthServlet</code> to use a different password).
* </p>
*
* <p>
* The resultant <code>keystore</code> (or <code>.keystore</code>)
* file must be copied to <code>$webappdir/WEB-INF/keystore</code>
* (on the IIS server).
* </p>
*
* <p>
* Now on the IIS server export the public key into a separate
* file like this:
* </p>
*
* <pre>
* keytool -export -alias ccmkey -file c:\temp\public_cert
* </pre>
*
* <p>
* You will need to type the keystore password in (<code>123456</code>).
*
* <p>
* Copy the public key to the CCM server, and import it into the
* keystore file on the CCM server like this:
* </p>
*
* <p>
* keytool -import -alias ccmkey -file /tmp/public_cert
* </p>
*
* <p>
* Make sure the <code>keystore</code> (or <code>.keystore</code>)
* file on the CCM file is copied to <code>$webappdir/WEB-INF/keystore</code>.
* </p>
*
* <p>
* Ensure that the public key has alias <code>ccmkey</code>
* and password <code>123456</code>.
* </p>
*
* @author Matt Booth, documentation by Richard W.M. Jones.
* @see com.arsdigita.auth.ntlm.NTLMLoginModule
*/
public class HTTPAuthServlet extends HttpServlet {
private Cipher m_encrypt;
// Leave same for backwards compatability
public static final String AUTH = "__camden_auth";
public static final String MAGIC = "camden";
/**
* Open the keystore and look for a key with the given alias. Create
* the encryption (ie. signing) cipher object.
*/
public void init() throws ServletException
{
// Create the encryption cypher.
PrivateKey privateKey = HTTPAuth.getConfig().getPrivateKey();
try {
m_encrypt = Cipher.getInstance(HTTPAuth.getConfig().getKeyCypher());
m_encrypt.init (Cipher.ENCRYPT_MODE, privateKey);
}
catch (GeneralSecurityException ex) {
throw new ServletException (ex);
}
}
public void doGet( HttpServletRequest req, HttpServletResponse res )
throws IOException, ServletException {
String nonce = req.getParameter ("nonce");
// If no nonce, just return the public key
if ( nonce == null ) {
throw new ServletException ("nonce parameter missing");
}
String returnURL = req.getParameter ("returnURL");
if ( returnURL == null ) {
throw new ServletException( "returnURL was not specified" );
}
// Generate an authorisation string of the form MAGICnonce|USERIDENT
String authString = MAGIC + nonce +
"|" + getRemoteUser (req);
try {
byte[] encBytes =
new byte[ m_encrypt.getOutputSize( authString.length() ) ];
m_encrypt.doFinal( authString.getBytes(), 0, authString.length(), encBytes );
authString = new BASE64Encoder().encode( encBytes );
authString = URLEncoder.encode( authString );
} catch( IllegalBlockSizeException e ) {
throw new ServletException( e );
} catch( BadPaddingException e ) {
throw new ServletException( e );
} catch( ShortBufferException e ) {
throw new ServletException( e );
}
if ( returnURL.indexOf( "?" ) == -1 ) {
returnURL += "?";
} else {
returnURL += "&";
}
returnURL += AUTH + "=" + authString;
res.sendRedirect( returnURL );
}
/**
* Note by RWMJ: I separated this out into a separate function just
* to make it simpler to test by hacking in hard-coded values.
*/
private String getRemoteUser (HttpServletRequest req) {
if (HTTPAuth.getConfig().isDebugMode()) {
return "example\\\\administrator";
} else {
return req.getRemoteUser ();
}
}
}