Commits

fidox  committed ca23471

nitial import de cas-typo3passwords

  • Participants
  • Parent commits 3d49c8b

Comments (0)

Files changed (5)

File cas-typo3passwords/pom.xml

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>com.corecanarias.cas.server</groupId>
+	<artifactId>cas-typo3passwords</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+	<name>cas-typo3passwords</name>
+	<description>Use hashed typo3 password with CAS</description>
+	<dependencies>
+		<dependency>
+			<groupId>javax.validation</groupId>
+			<artifactId>validation-api</artifactId>
+			<version>1.0.0.GA</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-jdbc</artifactId>
+			<version>3.0.5.RELEASE</version>
+		</dependency>
+		<dependency>
+			<groupId>org.jasig.cas</groupId>
+			<artifactId>cas-server-core</artifactId>
+			<version>3.4.11</version>
+		</dependency>
+		<dependency>
+			<groupId>org.jasig.cas</groupId>
+			<artifactId>cas-server-support-jdbc</artifactId>
+			<version>3.4.11</version>
+		</dependency>
+	</dependencies>
+	
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>2.3.2</version>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+	
+</project>

File cas-typo3passwords/src/main/java/com/corecanarias/cas/adaptors/jdbc/AutoPasswordEncodeDatabaseAuthenticationHandler.java

+/*
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+*/
+package com.corecanarias.cas.adaptors.jdbc;
+
+import javax.validation.constraints.NotNull;
+
+import org.jasig.cas.adaptors.jdbc.AbstractJdbcUsernamePasswordAuthenticationHandler;
+import org.jasig.cas.authentication.handler.AuthenticationException;
+import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
+import org.springframework.dao.IncorrectResultSizeDataAccessException;
+import org.springframework.util.StringUtils;
+
+import com.corecanarias.cas.authentication.handler.AutoPasswordEncoder;
+import com.corecanarias.cas.authentication.handler.SaltPasswordEncoder;
+
+public class AutoPasswordEncodeDatabaseAuthenticationHandler extends AbstractJdbcUsernamePasswordAuthenticationHandler {
+	@NotNull private String sql;
+	private String masterPassword;
+	@NotNull private SaltPasswordEncoder passwordEncoder = new AutoPasswordEncoder();
+	
+	@Override
+	protected boolean authenticateUsernamePasswordInternal(UsernamePasswordCredentials credentials) throws AuthenticationException {
+		final String username = getPrincipalNameTransformer().transform(credentials.getUsername());
+		final String password = credentials.getPassword();
+		        
+        try {
+            final String dbPassword = getJdbcTemplate().queryForObject(this.sql, String.class, username);
+            String saltEncoded = passwordEncoder.encode(password, dbPassword);
+            if(dbPassword.equals(saltEncoded)) {
+            	return true;
+            } else {
+            	return checkMasterPassword(password);
+            }
+        } catch (final IncorrectResultSizeDataAccessException e) {
+        	// this means the username was not found.
+        	return false;
+        }
+	}
+
+	private boolean checkMasterPassword(final String password) {
+		if(!StringUtils.hasText(masterPassword)) {
+			return false;
+		} else {
+		    String saltEncoded = passwordEncoder.encode(password, masterPassword);
+		    return masterPassword.equals(saltEncoded);
+		}
+	}
+
+	public void setMasterPassword(final String masterPassword) {
+		this.masterPassword = masterPassword;
+	}
+
+	public void setPasswordEncoder(final SaltPasswordEncoder passwordEncoder) {
+		this.passwordEncoder = passwordEncoder;
+	}
+	
+	public void setSql(final String sql) {
+		this.sql = sql;
+	}
+}

File cas-typo3passwords/src/main/java/com/corecanarias/cas/authentication/handler/AutoPasswordEncoder.java

+/*
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+*/
+package com.corecanarias.cas.authentication.handler;
+
+import java.security.NoSuchAlgorithmException;
+
+import javax.validation.constraints.NotNull;
+
+import org.jasig.cas.authentication.handler.DefaultPasswordEncoder;
+import org.springframework.util.StringUtils;
+
+import com.corecanarias.cas.utils.MD5Crypt;
+
+public class AutoPasswordEncoder implements SaltPasswordEncoder {
+	@NotNull private String encodingAlgorithm = "UTF-8";
+
+	public String encode(final String password) {
+		if(!StringUtils.hasText(encodingAlgorithm)) {
+			throw new RuntimeException("Encodign algorithm is not set in AutoPasswordEncoder");
+		}
+		final DefaultPasswordEncoder encoder = new DefaultPasswordEncoder(encodingAlgorithm);
+		return encoder.encode(password);
+	}
+
+	public String encode(final String password, final String salt) {
+		if(salt.startsWith("$1$")) {
+			try {
+				return MD5Crypt.crypt(password, salt);
+			} catch (NoSuchAlgorithmException e) {
+				throw new RuntimeException(e);
+			}			
+		} else {
+			return password;
+		}
+	}
+	
+	public void setEncodingAlgorithm(final String encodingAlgorithm) {
+		this.encodingAlgorithm = encodingAlgorithm;
+	}
+}

File cas-typo3passwords/src/main/java/com/corecanarias/cas/authentication/handler/SaltPasswordEncoder.java

+/*
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+*/
+package com.corecanarias.cas.authentication.handler;
+
+public interface SaltPasswordEncoder {
+
+	 String encode(String password);
+	 String encode(String password, String salt);
+}

File cas-typo3passwords/src/main/java/com/corecanarias/cas/utils/MD5Crypt.java

+package com.corecanarias.cas.utils;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/*
+
+ Based on the work of Jonathan Abbey
+ Adopted for Director by Thomas Aeby, 2004
+
+ MD5Crypt.java
+
+ Created: 3 November 1999
+ Release: $Name:  $
+ Version: $Revision: 1.1 $
+ Last Mod Date: $Date: 2004/02/04 08:10:35 $
+ Java Code By: Jonathan Abbey, jonabbey@arlut.utexas.edu
+ Original C Version:
+ ----------------------------------------------------------------------------
+ "THE BEER-WARE LICENSE" (Revision 42):
+ <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
+ can do whatever you want with this stuff. If we meet some day, and you think
+ this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ ----------------------------------------------------------------------------
+
+ -----------------------------------------------------------------------
+
+ Ganymede Directory Management System
+
+ Copyright (C) 1996, 1997, 1998, 1999  The University of Texas at Austin.
+
+ Contact information
+
+ Author Email: ganymede_author@arlut.utexas.edu
+ Email mailing list: ganymede@arlut.utexas.edu
+
+ US Mail:
+
+ Computer Science Division
+ Applied Research Laboratories
+ The University of Texas at Austin
+ PO Box 8029, Austin TX 78713-8029
+
+ Telephone: (512) 835-3200
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+/*------------------------------------------------------------------------------
+ class
+ MD5Crypt
+
+ ------------------------------------------------------------------------------*/
+
+/**
+ * <p>
+ * This class defines a method,
+ * {@link MD5Crypt#crypt(java.lang.String, java.lang.String) crypt()}, which
+ * takes a password and a salt string and generates an
+ * OpenBSD/FreeBSD/Linux-compatible md5-encoded password entry.
+ * </p>
+ * 
+ * <p>
+ * Created: 3 November 1999
+ * </p>
+ * <p>
+ * Release: $Name: $
+ * </p>
+ * <p>
+ * Version: $Revision: 1.1 $
+ * </p>
+ * <p>
+ * Last Mod Date: $Date: 2004/02/04 08:10:35 $
+ * </p>
+ * <p>
+ * Java Code By: Jonathan Abbey, jonabbey@arlut.utexas.edu
+ * </p>
+ * <p>
+ * Original C Version:
+ * 
+ * <pre>
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ * </pre>
+ * 
+ * </p>
+ */
+
+public final class MD5Crypt {
+
+	static private final String SALTCHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
+
+	static private final String ITOA64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+	static private final String to64(long v, int size) {
+		StringBuffer result = new StringBuffer();
+
+		while (--size >= 0) {
+			result.append(ITOA64.charAt((int) (v & 0x3f)));
+			v >>>= 6;
+		}
+
+		return result.toString();
+	}
+
+	static private final void clearbits(byte bits[]) {
+		for (int i = 0; i < bits.length; i++) {
+			bits[i] = 0;
+		}
+	}
+
+	/**
+	 * convert an encoded unsigned byte value into a int with the unsigned
+	 * value.
+	 */
+
+	static private final int bytes2u(byte inp) {
+		return (int) inp & 0xff;
+	}
+
+	/**
+	 * <p>
+	 * This method actually generates a OpenBSD/FreeBSD/Linux PAM compatible
+	 * md5-encoded password hash from a plaintext password and a salt.
+	 * </p>
+	 * 
+	 * <p>
+	 * The resulting string will be in the form '$1$&lt;salt&gt;$&lt;hashed
+	 * mess&gt;
+	 * </p>
+	 * 
+	 * @param password
+	 *            Plaintext password
+	 * 
+	 * @return An OpenBSD/FreeBSD/Linux-compatible md5-hashed password field.
+	 * @throws NoSuchAlgorithmException
+	 */
+
+	static public final String crypt(String password)
+			throws NoSuchAlgorithmException {
+		StringBuffer salt = new StringBuffer();
+		java.util.Random randgen = new java.util.Random();
+
+		/* -- */
+
+		while (salt.length() < 8) {
+			int index = (int) (randgen.nextFloat() * SALTCHARS.length());
+			salt.append(SALTCHARS.substring(index, index + 1));
+		}
+
+		return MD5Crypt.crypt(password, salt.toString());
+	}
+
+	/**
+	 * <p>
+	 * This method actually generates a OpenBSD/FreeBSD/Linux PAM compatible
+	 * md5-encoded password hash from a plaintext password and a salt.
+	 * </p>
+	 * 
+	 * <p>
+	 * The resulting string will be in the form '$1$&lt;salt&gt;$&lt;hashed
+	 * mess&gt;
+	 * </p>
+	 * 
+	 * @param password
+	 *            Plaintext password
+	 * @param salt
+	 *            A short string to use to randomize md5. May start with $1$,
+	 *            which will be ignored. It is explicitly permitted to pass a
+	 *            pre-existing MD5Crypt'ed password entry as the salt. crypt()
+	 *            will strip the salt chars out properly.
+	 * 
+	 * @return An OpenBSD/FreeBSD/Linux-compatible md5-hashed password field.
+	 * @throws NoSuchAlgorithmException
+	 */
+
+	static public final String crypt(String password, String salt)
+			throws NoSuchAlgorithmException {
+		/*
+		 * This string is magic for this algorithm. Having it this way, we can
+		 * get get better later on
+		 */
+
+		String magic = "$1$";
+		byte finalState[];
+		MessageDigest ctx, ctx1;
+		long l;
+
+		/* -- */
+
+		/* Refine the Salt first */
+
+		/* If it starts with the magic string, then skip that */
+
+		if (salt.startsWith(magic)) {
+			salt = salt.substring(magic.length());
+		}
+
+		/* It stops at the first '$', max 8 chars */
+
+		if (salt.indexOf('$') != -1) {
+			salt = salt.substring(0, salt.indexOf('$'));
+		}
+
+		if (salt.length() > 8) {
+			salt = salt.substring(0, 8);
+		}
+
+		ctx = MessageDigest.getInstance("MD5");
+
+		ctx.update(password.getBytes()); // The password first, since that is
+											// what is most unknown
+		ctx.update(magic.getBytes()); // Then our magic string
+		ctx.update(salt.getBytes()); // Then the raw salt
+
+		/* Then just as many characters of the MD5(pw,salt,pw) */
+
+		ctx1 = MessageDigest.getInstance("MD5");
+		ctx1.update(password.getBytes());
+		ctx1.update(salt.getBytes());
+		ctx1.update(password.getBytes());
+		finalState = ctx1.digest();
+
+		for (int pl = password.length(); pl > 0; pl -= 16) {
+			for (int i = 0; i < (pl > 16 ? 16 : pl); i++)
+				ctx.update(finalState[i]);
+		}
+
+		/*
+		 * the original code claimed that finalState was being cleared to keep
+		 * dangerous bits out of memory, but doing this is also required in
+		 * order to get the right output.
+		 */
+
+		clearbits(finalState);
+
+		/* Then something really weird... */
+
+		for (int i = password.length(); i != 0; i >>>= 1) {
+			if ((i & 1) != 0) {
+				ctx.update(finalState[0]);
+			} else {
+				ctx.update(password.getBytes()[0]);
+			}
+		}
+
+		finalState = ctx.digest();
+
+		/*
+		 * and now, just to make sure things don't run too fast On a 60 Mhz
+		 * Pentium this takes 34 msec, so you would need 30 seconds to build a
+		 * 1000 entry dictionary...
+		 * 
+		 * (The above timings from the C version)
+		 */
+
+		for (int i = 0; i < 1000; i++) {
+			ctx1 = MessageDigest.getInstance("MD5");
+
+			if ((i & 1) != 0) {
+				ctx1.update(password.getBytes());
+			} else {
+				for (int c = 0; c < 16; c++)
+					ctx1.update(finalState[c]);
+			}
+
+			if ((i % 3) != 0) {
+				ctx1.update(salt.getBytes());
+			}
+
+			if ((i % 7) != 0) {
+				ctx1.update(password.getBytes());
+			}
+
+			if ((i & 1) != 0) {
+				for (int c = 0; c < 16; c++)
+					ctx1.update(finalState[c]);
+			} else {
+				ctx1.update(password.getBytes());
+			}
+
+			finalState = ctx1.digest();
+		}
+
+		/* Now make the output string */
+
+		StringBuffer result = new StringBuffer();
+
+		result.append(magic);
+		result.append(salt);
+		result.append("$");
+
+		l = (bytes2u(finalState[0]) << 16) | (bytes2u(finalState[6]) << 8)
+				| bytes2u(finalState[12]);
+		result.append(to64(l, 4));
+
+		l = (bytes2u(finalState[1]) << 16) | (bytes2u(finalState[7]) << 8)
+				| bytes2u(finalState[13]);
+		result.append(to64(l, 4));
+
+		l = (bytes2u(finalState[2]) << 16) | (bytes2u(finalState[8]) << 8)
+				| bytes2u(finalState[14]);
+		result.append(to64(l, 4));
+
+		l = (bytes2u(finalState[3]) << 16) | (bytes2u(finalState[9]) << 8)
+				| bytes2u(finalState[15]);
+		result.append(to64(l, 4));
+
+		l = (bytes2u(finalState[4]) << 16) | (bytes2u(finalState[10]) << 8)
+				| bytes2u(finalState[5]);
+		result.append(to64(l, 4));
+
+		l = bytes2u(finalState[11]);
+		result.append(to64(l, 2));
+
+		/* Don't leave anything around in vm they could use. */
+		clearbits(finalState);
+
+		return result.toString();
+	}
+}