/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.wicket.security.hive.authentication; import org.apache.wicket.security.authentication.LoginException; /** * A LoginContext is little more than a factory to create a {@link Subject} and can be * discarded afterwards. Usually it contains some credentials such as username and * password. Note that generally it is no a good idea to store those type of credentials * in the session, so if you plan on keeping this context in the session be sure to clear * them before you return a Subject in {@link #login()}. Some applications will require * you to login with two or more different LoginContexts before a user is fully * authenticated. For that purpose a sortOrder is available in the context. which is used * in descending order to pass authentication requests to the subjects until one of them * authenticates. Sort orders are >=0 and are not required to have an interval of 1. * For example 0, 5,6 are all perfectly legal sort orders for one user. Duplicates are * also allowed, in that case they are queried in reverse order of login. The context also * contains a flag to indicate if an additional login is allowed. Note that both the sort * order and the additional login flag must be constant. Also note that all LoginContexts * of the same class and with the same sort order are equal, thus for logoff you do not * need to keep a reference to the context but can simply use a new instance. * * @author marrink * @see #preventsAdditionalLogins() */ public abstract class LoginContext { private final int sortOrder; private final boolean additionalLoginsPrevented; /** * Constructs a context for single login applications. At sortorder 0 and preventing * additional logins. */ public LoginContext() { this(0, false); } /** * Constructs a new context at the specified sort order. Additional logins are * prevented. This constructor is usually used in mult-login scenario's for the * context with the the highest sort order. * * @param sortOrder * a number of 0 or higher. */ public LoginContext(int sortOrder) { this(sortOrder, false); } /** * Constructs a new context with sort order 0 and a customizable flag for preventing * additional logins. This constructor is mostly used in multi-login scenario's. * * @param allowAdditionalLogings * indicates if this context allows multiple subjects for one user and thus * allows the user to gain more permissions on the fly. */ public LoginContext(boolean allowAdditionalLogings) { this(0, allowAdditionalLogings); } /** * Constructs a new context with customizable sort order and flag for preventing * additional logins. This constructor is mostly used in multi-login scenario's. * * @param sortOrder * @param allowAdditionalLogins */ public LoginContext(int sortOrder, boolean allowAdditionalLogins) { if (sortOrder < 0) throw new IllegalArgumentException("0 is the lowest sort order allowed, not " + sortOrder); this.sortOrder = sortOrder; this.additionalLoginsPrevented = !allowAdditionalLogins; } /** * Perform a login. If the login fails in any way a {@link LoginException} must be * thrown rather then returning null. You should clear all sensitive data stored in * this context before returning the subject or throwing an exception. * * @return a {@link Subject}, never null. * @throws LoginException * if an exception occurs or if the subject could not login for some other * reason */ public abstract Subject login() throws LoginException; /** * Indicates the sort order of this context. the higher the value the more you are * authorized / authenticated for. * * @return the level */ protected final int getSortOrder() { return sortOrder; } /** * @see java.lang.Object#hashCode() */ @Override public final int hashCode() { final int PRIME = 31; int result = 1; // classname to get consistent hash over different jvm instances. result = PRIME * result + getClass().getName().hashCode(); result = PRIME * result + sortOrder; return result; } /** * A loginContext is equal to a LoginContext of the same class (not subclass) and * level. * * @see java.lang.Object#equals(java.lang.Object) */ @Override public final boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!getClass().getName().equals(obj.getClass().getName())) return false; final LoginContext other = (LoginContext) obj; return sortOrder == other.sortOrder; } /** * Signals that no additional context should be allowed to login. The return value * must be constant from one invocation to another for this instance. This flag is * checked once by the container immediately after {@link #login()}. Note in a multi * login environment you will want your logincontext with the highest possible sort * order to prevent additional logins. In a single login environment your logincontext * should always prevent additional logins. * * @return true if you do not want additional logins for this session, false * otherwise. */ public boolean preventsAdditionalLogins() { return additionalLoginsPrevented; } /** * Callback to take some action after a subject has been logged off. Note that the * LoginContext receiving this notification is not necessarily the same instance that * created the subject. This is because Swarm does not store LoginContexts as they may * contain sensitive data. By default this method does nothing. * * @param subject * the user that has just been logged off */ public void notifyLogoff(Subject subject) { } }