Browse Source

SEC-716: Default (non-web) AuthenticationDetailsSource implementation.

Luke Taylor 17 years ago
parent
commit
f8d855f1a2

+ 81 - 0
core/src/main/java/org/springframework/security/ui/AuthenticationDetails.java

@@ -0,0 +1,81 @@
+package org.springframework.security.ui;
+
+import java.io.Serializable;
+
+/**
+* A holder of the context as a string.
+*
+* @author Ruud Senden
+* @since 2.0
+*/
+public class AuthenticationDetails implements Serializable {
+   //~ Instance fields ================================================================================================
+
+   private String context;
+
+   //~ Constructors ===================================================================================================
+
+   /**
+    * Constructor.
+    *
+    * @param context that the authentication request is initiated from
+    */
+   public AuthenticationDetails(Object context) {
+       this.context = context==null?"":context.toString();
+       doPopulateAdditionalInformation(context);
+   }
+
+   protected AuthenticationDetails() {
+       throw new IllegalArgumentException("Cannot use default constructor");
+   }
+
+   //~ Methods ========================================================================================================
+
+   /**
+    * Provided so that subclasses can populate additional information.
+    *
+    * @param request that the authentication request was received from
+    */
+   protected void doPopulateAdditionalInformation(Object context) {}
+
+   public boolean equals(Object obj) {
+       if (obj instanceof AuthenticationDetails) {
+           AuthenticationDetails rhs = (AuthenticationDetails) obj;
+
+           if ((context == null) && (rhs.getContext() != null)) {
+               return false;
+           }
+
+           if ((context != null) && (rhs.getContext() == null)) {
+               return false;
+           }
+
+           if (context != null) {
+               if (!context.equals(rhs.getContext())) {
+                   return false;
+               }
+           }
+
+           return true;
+       }
+
+       return false;
+   }
+
+   /**
+    * Indicates the context.
+    *
+    * @return the address
+    */
+   public String getContext() {
+       return context;
+   }
+
+   public String toString() {
+       StringBuffer sb = new StringBuffer();
+       sb.append(super.toString() + ": ");
+       sb.append("Context: " + this.getContext());
+       
+       return sb.toString();
+   }
+}

+ 81 - 0
core/src/main/java/org/springframework/security/ui/AuthenticationDetailsSourceImpl.java

@@ -0,0 +1,81 @@
+package org.springframework.security.ui;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import org.springframework.security.ui.AuthenticationDetailsSource;
+import org.springframework.util.Assert;
+import org.springframework.util.ReflectionUtils;
+
+/**
+ * Base implementation of {@link AuthenticationDetailsSource}.
+ * <p>
+ * By default will create an instance of <code>AuthenticationDetails</code>.
+ * Any object that accepts an <code>Object</code> as its sole constructor can
+ * be used instead of this default.
+ * </p>
+ * 
+ * @author Ruud Senden
+ * @since 2.0
+ */
+public class AuthenticationDetailsSourceImpl implements AuthenticationDetailsSource {
+	//~ Instance fields ================================================================================================
+
+	private Class clazz = AuthenticationDetails.class;
+	
+	//~ Methods ========================================================================================================
+
+	public Object buildDetails(Object context) {
+		try {
+			Constructor constructor = getFirstMatchingConstructor(context);
+			return constructor.newInstance(new Object[] { context });
+		} catch (NoSuchMethodException ex) {
+			ReflectionUtils.handleReflectionException(ex);
+		} catch (InvocationTargetException ex) {
+			ReflectionUtils.handleReflectionException(ex);
+		} catch (InstantiationException ex) {
+			ReflectionUtils.handleReflectionException(ex);
+		} catch (IllegalAccessException ex) {
+			ReflectionUtils.handleReflectionException(ex);
+		}
+
+		return null;
+	}
+
+	/**
+	 * Return the first matching constructor that can take the given object
+	 * as an argument. Please note that we cannot use 
+	 * getDeclaredConstructor(new Class[]{object.getClass()})
+	 * as this will only match if the constructor argument type matches
+	 * the object type exactly (instead of checking whether it is assignable)
+	 * 
+	 * @param object the object for which to find a matching constructor
+	 * @return a matching constructor for the given object
+	 * @throws NoSuchMethodException if no matching constructor can be found
+	 */
+	private Constructor getFirstMatchingConstructor(Object object) throws NoSuchMethodException {
+		Constructor[] constructors = clazz.getDeclaredConstructors();
+		Constructor constructor = null;
+		for (int i = 0; i < constructors.length; i++) {
+			Class[] parameterTypes = constructors[i].getParameterTypes();
+			if (parameterTypes.length == 1 && (object == null || parameterTypes[i].isInstance(object))) {
+				constructor = constructors[i];
+				break;
+			}
+		}
+
+		if (constructor == null) {
+			if (object == null) {
+				throw new NoSuchMethodException("No constructor found that can take a single argument");
+			} else {
+				throw new NoSuchMethodException("No constructor found that can take a single argument of type " + object.getClass());
+			}
+		}
+		return constructor;
+	}
+
+	public void setClazz(Class clazz) {
+		Assert.notNull(clazz, "Class required");
+		this.clazz = clazz;
+	}
+}