Commit fec04fd6 authored by Derek DeMoro's avatar Derek DeMoro Committed by derek

Working on GSSAPI provider.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/branches/3_3_1_branch@8228 b35dd754-fafc-0310-a699-88a17e54d16e
parent 678adeae
/**
* $RCSfile$
* $Revision: $
* $Date: 2006-04-20 10:46:24 -0500 (Thu, 20 Apr 2006) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.openfire.sasl;
/**
* Provider for authorization policies. Policy decisions are
* not based on any storage or specific options. They are
* ment to be broad sweeping policies, and are often implemented
* with a simple pattern matching algorithm. For a large
* majority of sites, a policy will be all that is required.
*
* Users that wish to integrate with their own authorization
* system must extend this class and implement the
* AuthorizationProvider interface then register the class
* with Openfire in the <tt>openfire.xml</tt> file. An entry
* in that file would look like the following:
*
* <pre>
* &lt;provider&gt;
* &lt;authorizationpolicy&gt;
* &lt;classlist&gt;com.foo.auth.CustomPolicyProvider&lt;/classlist&gt;
* &lt;/authorizationpolicy&gt;
* &lt;/provider&gt;</pre>
*
* @author Jay Kline
*/
public abstract class AbstractAuthorizationPolicy implements AuthorizationPolicy {
/**
* Returns true if the principal is explicity authorized to the JID
*
* @param username The username requested.
* @param principal The principal requesting the username.
* @return true is the user is authorized to be principal
*/
public abstract boolean authorize(String username, String principal);
}
\ No newline at end of file
...@@ -11,13 +11,14 @@ ...@@ -11,13 +11,14 @@
package org.jivesoftware.openfire.sasl; package org.jivesoftware.openfire.sasl;
import org.jivesoftware.openfire.user.UserAlreadyExistsException;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.openfire.user.UserProvider;
import org.jivesoftware.util.ClassUtils; import org.jivesoftware.util.ClassUtils;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.StringTokenizer;
/** /**
* Manages the AuthorizationProvider objects. * Manages the AuthorizationProvider objects.
...@@ -42,48 +43,28 @@ import java.util.StringTokenizer; ...@@ -42,48 +43,28 @@ import java.util.StringTokenizer;
*/ */
public class AuthorizationManager { public class AuthorizationManager {
private static ArrayList<AuthorizationPolicy> providers =
new ArrayList<AuthorizationPolicy>();
private static AuthorizationManager instance = new AuthorizationManager(); private static AuthorizationManager instance = new AuthorizationManager();
private static AuthorizationPolicy authorizationProvider;
static { static {
String classList = JiveGlobals.getXMLProperty("provider.authorization.classList"); String className = JiveGlobals.getXMLProperty("provider.authorization.className");
if (classList != null) { if (className != null) {
StringTokenizer st = new StringTokenizer(classList, " ,\t\n\r\f");
while (st.hasMoreTokens()) {
String s_provider = st.nextToken();
try { try {
Class c_provider = ClassUtils.forName(s_provider); Class c_provider = ClassUtils.forName(className);
AuthorizationPolicy provider = AuthorizationPolicy provider = (AuthorizationPolicy)(c_provider.newInstance());
(AuthorizationPolicy) (c_provider.newInstance()); Log.debug("AuthorizationManager: Loaded " + provider);
Log.debug("AuthorizationManager: Loaded " + s_provider); authorizationProvider = provider;
providers.add(provider);
} catch (Exception e) {
Log.error("Error loading AuthorizationProvider: " + s_provider + "\n" + e);
} }
catch (Exception e) {
Log.error("Error loading AuthorizationProvider: " + className + "\n" + e);
} }
} }
if (providers.isEmpty()) {
if (authorizationProvider == null) {
Log.debug("No AuthorizationProvider's found. Loading DefaultAuthorizationPolicy"); Log.debug("No AuthorizationProvider's found. Loading DefaultAuthorizationPolicy");
providers.add(new DefaultAuthorizationPolicy());
} }
} }
private AuthorizationManager() {
}
/**
* Returns the currently-installed AuthorizationProvider. Warning: You
* should not be calling the AuthorizationProvider directly to perform
* authorizations, it will not take into account the policy selected in
* the <tt>openfire.xml</tt>. Use @see{authorize} in this class, instead.
*
* @return the current AuthorizationProvider.
*/
public static Collection<AuthorizationPolicy> getAuthorizationProviders() {
return providers;
}
/** /**
* Returns a singleton AuthorizationManager instance. * Returns a singleton AuthorizationManager instance.
...@@ -94,19 +75,53 @@ public class AuthorizationManager { ...@@ -94,19 +75,53 @@ public class AuthorizationManager {
return instance; return instance;
} }
private AuthorizationManager() {
}
/** /**
* Authorize the authenticated used to the requested username. This uses the * Authorize the authenticated used to the requested username. This uses the
* selected the selected AuthenticationProviders. * GSSAPIAuthProvider if it is the specified provider.
* *
* @param username the username.
* @param principal the principal.
* @return true if the user is authorized. * @return true if the user is authorized.
*/ */
public static boolean authorize(String username, String principal) {
boolean authorized = false;
if (authorizationProvider != null) {
authorized = authorizationProvider.authorize(username, principal);
if (!authorized) {
return false;
}
}
public static boolean authorize(String authorId, String authenId) { // If the user is authorized, we want to check if the user is listed as a
for (AuthorizationPolicy ap : providers) { // member of the <code>UserProvider</code>, and if not, add the user (if writable).
if (ap.authorize(authorId, authenId)) { // See if the user exists in the database. If not, automatically create them.
UserManager userManager = UserManager.getInstance();
try {
userManager.getUser(username);
}
catch (UserNotFoundException userNotFound) {
try {
Log.debug("Automatically creating new user account for " + username);
// Create user; use a random password for better safety in the future.
// Note that we have to go to the user provider directly -- because the
// provider is read-only, UserManager will usually deny access to createUser.
UserProvider userProvider = UserManager.getUserProvider();
if (userProvider.isReadOnly()) {
Log.error("Error: Unable to add the user. The UserProvider is not writable.");
}
UserManager.getUserProvider().createUser(username, StringUtils.randomString(8),
null, null);
return true; return true;
} }
catch (UserAlreadyExistsException uaee) {
// Ignore.
} }
return false; }
return true;
} }
} }
/**
* $RCSfile$
* $Revision: $
* $Date: 2006-04-20 10:46:24 -0500 (Thu, 20 Apr 2006) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.openfire.sasl;
import org.jivesoftware.openfire.XMPPServer;
/**
* This policy will authorize any principal that matches exactly the full
* JID (REALM and server name must be the same if using GSSAPI) or any
* principal that matches exactly the username (without REALM or server
* name). This does exactly what users expect if not supplying a seperate
* principal for authentication.
*
* @author Jay Kline
*/
public class DefaultAuthorizationPolicy implements AuthorizationPolicy {
private String serverName;
public DefaultAuthorizationPolicy() {
serverName = XMPPServer.getInstance().getServerInfo().getName();
}
/**
* Returns true if the principal is explicity authorized to the JID
*
* @param username The username requested.
* @param principal The principal requesting the username.
* @return true is the user is authorized to be principal
*/
public boolean authorize(String username, String principal) {
return (principal.equals(username) || principal.equals(username + "@" + serverName));
}
/**
* Returns the short name of the Policy
*
* @return The short name of the Policy
*/
public String name() {
return "Default Policy";
}
/**
* Returns a description of the Policy
*
* @return The description of the Policy.
*/
public String description() {
return "This policy will authorize any principal that matches exactly the full " +
"JID (REALM and server name must be the same if using GSSAPI) or any principal " +
"that matches exactly the username (without REALM or server name). This does " +
"exactly what users expect if not supplying a seperate principal for authentication.";
}
}
\ No newline at end of file
/**
* $Revision$
* $Date$
*
* Copyright (C) 1999-2005 Jive Software. All rights reserved.
* This software is the proprietary information of Jive Software. Use is subject to license terms.
*/
package org.jivesoftware.openfire.sasl;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.util.JiveGlobals;
/**
* Provider for gsaapi authorization using one of the 3 policy states.
*
* @author Derek DeMoro
*/
public class GSSAPIAuthorizationProvider implements AuthorizationPolicy {
private AuthPolicy currentPolicy;
/**
* AuthorizationPolicies defines different authorization types using GSAAPI.
*/
private static enum AuthPolicy {
/**
* This policy will authorize any principal who's username matches exactly
* the username of the JID. This means when cross realm authentication is
* allowed, user@REALM_A.COM and user@REALM_B.COM could both authorize as
* user@servername, so there is some risk here. But if usernames across the
*/
loose,
/**
* This policy will authorize any principal who:
* <p/>
* <li> Username of principal matches exactly the username of the JID </li>
* <li> The user principal's realm matches exactly the realm of the server.</li>
* Note that the realm may not match the servername, and in fact for this
* policy to be useful it will not match the servername. RFC3920 Section
* 6.1, item 7 states that if the principal (authorization entity) is the
* same as the JID (initiating entity), its MUST NOT provide an authorization
* identity. In practice however, GSSAPI will provide both. (Note: Ive
* not done extensive testing on this)
*/
strict
}
public GSSAPIAuthorizationProvider() {
}
/**
* Authorize the authenticated used to the requested username. This uses the
* GSSAPIAuthProvider if it is the specified provider.
*
* @param username the username.
* @param principal the principal.
* @return true if the user is authorized.
*/
public boolean authorize(String username, String principal) {
// Find set Authorization Policy
// Find set Authorization Policy
final String policy = JiveGlobals.getProperty("gssapi.auth.policy", "strict");
if ("strict".equals(policy)) {
currentPolicy = AuthPolicy.strict;
}
else if ("loose".equals(policy)) {
currentPolicy = AuthPolicy.loose;
}
// Handle authorization policy
if (currentPolicy == AuthPolicy.strict) {
String serverName = XMPPServer.getInstance().getServerInfo().getName();
return (principal.equals(username) || principal.equals(username + "@" + serverName));
}
else if (currentPolicy == AuthPolicy.loose) {
return (principal.startsWith(username + "@"));
}
return false;
}
public String name() {
return "GSSAPI Authorization Policy";
}
public String description() {
return "This policy will authorize a principal based on the set policy for the server.";
}
}
/**
* $RCSfile$
* $Revision: $
* $Date: 2006-04-20 10:46:24 -0500 (Thu, 20 Apr 2006) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.openfire.sasl;
/**
* This policy will authorize any principal who's username matches exactly
* the username of the JID. This means when cross realm authentication is
* allowed, user@REALM_A.COM and user@REALM_B.COM could both authorize as
* user@servername, so there is some risk here. But if usernames across the
*
* @author Jay Kline
*/
public class LooseAuthorizationPolicy implements AuthorizationPolicy {
/**
* Returns true if the principal is explicity authorized to the JID
*
* @param username The username requested.
* @param principal The principal requesting the username.
* @return true is the user is authorized to be principal
*/
public boolean authorize(String username, String principal) {
return (principal.startsWith(username + "@"));
}
/**
* Returns the short name of the Policy
*
* @return The short name of the Policy
*/
public String name() {
return "Loose Authorization Policy";
}
/**
* Returns a description of the Policy
*
* @return The description of the Policy.
*/
public String description() {
return "This policy will authorize any principal who's username matches exactly the username of the JID. This means when cross realm authentication is allowed, user@REALM_A.COM and user@REALM_B.COM could both authorize as user@servername, so there is some risk here. But if usernames across the realms are unique, this can be very helpful.";
}
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision: $
* $Date: 2006-04-20 10:46:24 -0500 (Thu, 20 Apr 2006) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.openfire.sasl;
import org.jivesoftware.util.JiveGlobals;
/**
* This policy will authorize any principal who:
* <p/>
* <li> Username of principal matches exactly the username of the JID </li>
* <li> The user principal's realm matches exactly the realm of the server.</li>
* Note that the realm may not match the servername, and in fact for this
* policy to be useful it will not match the servername. RFC3920 Section
* 6.1, item 7 states that if the principal (authorization entity) is the
* same as the JID (initiating entity), its MUST NOT provide an authorization
* identity. In practice however, GSSAPI will provide both. (Note: Ive
* not done extensive testing on this)
*
* @author Jay Kline
*/
public class StrictAuthorizationPolicy implements AuthorizationPolicy {
/**
* Returns true if the principal is explicity authorized to the JID
*
* @param username The username requested.
* @param principal The principal requesting the username.
* @return true is the user is authorized to be principal
*/
public boolean authorize(String username, String principal) {
return (principal.equals(username + "@" + JiveGlobals.getXMLProperty("sasl.realm")));
}
/**
* Returns the short name of the Policy
*
* @return The short name of the Policy
*/
public String name() {
return "Strict Policy";
}
/**
* Returns a description of the Policy
*
* @return The description of the Policy.
*/
public String description() {
return "This policy will authorize any principal whos username matches exactly the username of the JID and whos realm matches exactly the realm of the server.";
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment