Commit 5976dfbb authored by Derek DeMoro's avatar Derek DeMoro Committed by derek

Need to ensure backwards compatibilty with Sasl Mechs and AuthorizationPolicies.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/branches/3_3_1_branch@8265 b35dd754-fafc-0310-a699-88a17e54d16e
parent 239ce678
/**
* $RCSfile$
* $Revision: $
* $Date: 2006-04-07 09:28:54 -0500 (Fri, 07 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.ldap;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.openfire.sasl.AbstractAuthorizationProvider;
import org.jivesoftware.openfire.sasl.AuthorizationPolicy;
import org.xmpp.packet.JID;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
/**
* Provider for authorization using LDAP. Checks if the authenticated
* principal is in the user's LDAP object using the authorizeField
* from the <tt>openfire.xml</tt> file. An entry in that file would
* look like the following:
*
* <pre>
* &lt;ldap&gt;
* &lt;authorizeField&gt; k5login &lt;/authorizeField&gt;
* &lt;/ldap&gt;</pre>
*
* This implementation requires that LDAP be configured, obviously.
*
* @author Jay Kline
*/
public class LdapAuthorizationProvider extends AbstractAuthorizationProvider implements AuthorizationPolicy {
private LdapManager manager;
private String usernameField;
private String authorizeField;
public LdapAuthorizationProvider() {
manager = LdapManager.getInstance();
usernameField = manager.getUsernameField();
authorizeField = JiveGlobals.getXMLProperty("ldap.authorizeField", "k5login");
}
/**
* Returns if the principal is explicity authorized to the JID, throws
* an UnauthorizedException otherwise
*
* @param username The username requested.import org.jivesoftware.openfire.ldap.*;
* @param principal The principal requesting the username.
*
*/
public boolean authorize(String username, String principal) {
return getAuthorized(username).contains(principal);
}
/**
* Returns a String Collection of principals that are authorized to use
* the named user.
*
* @param username the username.
* @return A String Collection of principals that are authorized.
*/
public Collection<String> getAuthorized(String username) {
// Un-escape Node
username = JID.unescapeNode(username);
Collection<String> authorized = new ArrayList<String>();
DirContext ctx = null;
try {
String userDN = manager.findUserDN(username);
// Load record.
String[] attributes = new String[]{
usernameField,
authorizeField
};
ctx = manager.getContext();
Attributes attrs = ctx.getAttributes(userDN, attributes);
Attribute authorizeField_a = attrs.get(manager.getNameField());
if (authorizeField_a != null) {
for(Enumeration e = authorizeField_a.getAll(); e.hasMoreElements();) {
authorized.add((String)e.nextElement());
}
}
return authorized;
}
catch (Exception e) {
// Ignore.
}
finally {
try {
if (ctx != null) {
ctx.close();
}
}
catch (Exception ignored) {
// Ignore.
}
}
return authorized;
}
/**
* Returns false, this implementation is not writeable.
*
* @return False.
*/
public boolean isWritable() {
return false;
}
/**
* Always throws UnsupportedOperationException.
*
* @param username The username.
* @param principal The principal authorized to use the named user.
* @throws UnsupportedOperationException If this AuthorizationProvider cannot be updated.
*/
public void addAuthorized(String username, String principal) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Always throws UnsupportedOperationException.
*
* @param username The username.
* @param principals The Collection of principals authorized to use the named user.
*/
public void addAuthorized(String username, Collection<String> principals) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Always throws UnsupportedOperationException.
*
* @param username The username.
* @param principals The Collection of principals authorized to use the named user.
* @throws UnsupportedOperationException If this AuthorizationProvider cannot be updated.
*/
public void setAuthorized(String username, Collection<String> principals) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Returns the short name of the Policy
*
* @return The short name of the Policy
*/
public String name() {
return "LDAP Authorization Provider";
}
/**
* Returns a description of the Policy
*
* @return The description of the Policy.
*/
public String description() {
return "Provider for authorization using LDAP. Checks if the authenticated principal is in the user's LDAP object using the authorizeField property.";
}
}
\ No newline at end of file
......@@ -15,10 +15,6 @@ import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.jivesoftware.util.CertificateManager;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.AuthFactory;
import org.jivesoftware.openfire.auth.AuthToken;
......@@ -26,28 +22,38 @@ import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.openfire.session.IncomingServerSession;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.CertificateManager;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils;
import org.xmpp.packet.JID;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
import java.io.UnsupportedEncodingException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
/**
* SASLAuthentication is responsible for returning the available SASL mechanisms to use and for
* actually performing the SASL authentication.<p>
*
* <p/>
* The list of available SASL mechanisms is determined by:
* <ol>
* <li>The type of {@link org.jivesoftware.openfire.user.UserProvider} being used since
* some SASL mechanisms require the server to be able to retrieve user passwords</li>
* <li>Whether anonymous logins are enabled or not.</li>
* <li>Whether shared secret authentication is enabled or not.</li>
* <li>Whether the underlying connection has been secured or not.</li>
* <li>The type of {@link org.jivesoftware.openfire.user.UserProvider} being used since
* some SASL mechanisms require the server to be able to retrieve user passwords</li>
* <li>Whether anonymous logins are enabled or not.</li>
* <li>Whether shared secret authentication is enabled or not.</li>
* <li>Whether the underlying connection has been secured or not.</li>
* </ol>
*
* @author Hao Chen
......@@ -94,7 +100,8 @@ public class SASLAuthentication {
}
}
@SuppressWarnings({"UnnecessarySemicolon"}) // Support for QDox Parser
@SuppressWarnings({"UnnecessarySemicolon"})
// Support for QDox Parser
public enum Status {
/**
* Entity needs to respond last challenge. Session is still negotiating
......@@ -174,7 +181,7 @@ public class SASLAuthentication {
* if the entity is expected to send a response to a challenge.
*
* @param session the session that is authenticating with the server.
* @param doc the stanza sent by the authenticating entity.
* @param doc the stanza sent by the authenticating entity.
* @return value that indicates whether the authentication has finished either successfully
* or not or if the entity is expected to send a response to a challenge.
* @throws UnsupportedEncodingException If UTF-8 charset is not supported.
......@@ -244,7 +251,7 @@ public class SASLAuthentication {
break;
case RESPONSE:
// Store the requested SASL mechanism by the client
mechanism = (String) session.getSessionData("SaslMechanism");
mechanism = (String)session.getSessionData("SaslMechanism");
if (mechanism.equalsIgnoreCase("PLAIN") &&
mechanisms.contains("PLAIN")) {
status = doPlainAuthentication(session, doc);
......@@ -256,7 +263,7 @@ public class SASLAuthentication {
status = doSharedSecretAuthentication(session, doc);
}
else if (mechanisms.contains(mechanism)) {
SaslServer ss = (SaslServer) session.getSessionData("SaslServer");
SaslServer ss = (SaslServer)session.getSessionData("SaslServer");
if (ss != null) {
boolean ssComplete = ss.isComplete();
String response = doc.getTextTrim();
......@@ -469,10 +476,10 @@ public class SASLAuthentication {
return Status.authenticated;
}
// Check that hostname matches the one provided in a certificate
SocketConnection connection = (SocketConnection) session.getConnection();
SocketConnection connection = (SocketConnection)session.getConnection();
try {
for (Certificate certificate : connection.getSSLSession().getPeerCertificates()) {
if (CertificateManager.getPeerIdentities((X509Certificate) certificate)
if (CertificateManager.getPeerIdentities((X509Certificate)certificate)
.contains(hostname)) {
authenticationSuccessful(session, hostname, null);
return Status.authenticated;
......@@ -487,8 +494,7 @@ public class SASLAuthentication {
}
private static Status doSharedSecretAuthentication(Session session, Element doc)
throws UnsupportedEncodingException
{
throws UnsupportedEncodingException {
String secretDigest;
String response = doc.getTextTrim();
if (response == null || response.length() == 0) {
......@@ -528,7 +534,7 @@ public class SASLAuthentication {
}
private static void authenticationSuccessful(Session session, String username,
byte[] successData) {
byte[] successData) {
StringBuilder reply = new StringBuilder(80);
reply.append("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"");
if (successData != null) {
......@@ -541,7 +547,7 @@ public class SASLAuthentication {
session.getConnection().deliverRawText(reply.toString());
// We only support SASL for c2s
if (session instanceof ClientSession) {
((ClientSession) session).setAuthToken(new AuthToken(username));
((ClientSession)session).setAuthToken(new AuthToken(username));
}
else if (session instanceof IncomingServerSession) {
String hostname = username;
......@@ -549,7 +555,7 @@ public class SASLAuthentication {
session.setAddress(new JID(null, hostname, null));
// Add the validated domain as a valid domain. The remote server can
// now send packets from this address
((IncomingServerSession) session).addValidatedDomain(hostname);
((IncomingServerSession)session).addValidatedDomain(hostname);
}
}
......@@ -559,7 +565,7 @@ public class SASLAuthentication {
reply.append("<not-authorized/></failure>");
session.getConnection().deliverRawText(reply.toString());
// Give a number of retries before closing the connection
Integer retries = (Integer) session.getSessionData("authRetries");
Integer retries = (Integer)session.getSessionData("authRetries");
if (retries == null) {
retries = 1;
}
......@@ -567,7 +573,7 @@ public class SASLAuthentication {
retries = retries + 1;
}
session.setSessionData("authRetries", retries);
if (retries >= JiveGlobals.getIntProperty("xmpp.auth.retries", 3) ) {
if (retries >= JiveGlobals.getIntProperty("xmpp.auth.retries", 3)) {
// Close the connection
session.getConnection().close();
}
......@@ -576,7 +582,7 @@ public class SASLAuthentication {
/**
* Adds a new SASL mechanism to the list of supported SASL mechanisms by the server. The
* new mechanism will be offered to clients and connection managers as stream features.<p>
*
* <p/>
* Note: this method simply registers the SASL mechanism to be advertised as a supported
* mechanism by Openfire. Actual SASL handling is done by Java itself, so you must add
* the provider to Java.
......@@ -607,7 +613,7 @@ public class SASLAuthentication {
public static Set<String> getSupportedMechanisms() {
Set<String> answer = new HashSet<String>(mechanisms);
// Clean up not-available mechanisms
for (Iterator<String> it=answer.iterator(); it.hasNext();) {
for (Iterator<String> it = answer.iterator(); it.hasNext();) {
String mech = it.next();
if (mech.equals("CRAM-MD5") || mech.equals("DIGEST-MD5")) {
// Check if the user provider in use supports passwords retrieval. Accessing
......@@ -652,8 +658,7 @@ public class SASLAuthentication {
mech.equals("DIGEST-MD5") ||
mech.equals("CRAM-MD5") ||
mech.equals("GSSAPI") ||
mech.equals("JIVE-SHAREDSECRET"))
{
mech.equals("JIVE-SHAREDSECRET")) {
Log.debug("SASLAuthentication: Added " + mech + " to mech list");
mechanisms.add(mech);
}
......@@ -661,12 +666,9 @@ public class SASLAuthentication {
if (mechanisms.contains("GSSAPI")) {
if (JiveGlobals.getXMLProperty("sasl.gssapi.config") != null) {
System.setProperty("java.security.krb5.debug",
JiveGlobals.getXMLProperty("sasl.gssapi.debug", "false"));
System.setProperty("java.security.auth.login.config",
JiveGlobals.getXMLProperty("sasl.gssapi.config"));
System.setProperty("javax.security.auth.useSubjectCredsOnly",
JiveGlobals.getXMLProperty("sasl.gssapi.useSubjectCredsOnly", "false"));
System.setProperty("java.security.krb5.debug", JiveGlobals.getXMLProperty("sasl.gssapi.debug", "false"));
System.setProperty("java.security.auth.login.config", JiveGlobals.getXMLProperty("sasl.gssapi.config"));
System.setProperty("javax.security.auth.useSubjectCredsOnly", JiveGlobals.getXMLProperty("sasl.gssapi.useSubjectCredsOnly", "false"));
}
else {
//Not configured, remove the option.
......
......@@ -15,14 +15,14 @@ import java.util.Collection;
/**
* Provider for authorization. Unlike the AbstractAuthorizationPolicy
* class, this is intended for classes that need a more "heavyweight"
* class, this is intended for classes that need a more "heavyweight"
* solution, often that requires consulting some storage or external
* entity about each specific case. This class allows individual mappings
* between authenticated principals and usernames, and if the storage
* mechanism allows it, management of those mappings.
*
* Users that wish to integrate with their own authorization
* system must extend this class and implement the
* 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:
......@@ -46,7 +46,7 @@ public abstract class AbstractAuthorizationProvider implements AuthorizationPoli
* @return true is the user is authorized to be principal
*/
public abstract boolean authorize(String username, String principal);
/**
* Returns a String Collection of principals that are authorized to use
* the named user.
......@@ -55,16 +55,16 @@ public abstract class AbstractAuthorizationProvider implements AuthorizationPoli
* @return A String Collection of principals that are authorized.
*/
public abstract Collection<String> getAuthorized(String username);
/**
* Returns true if this AuthorizationProvider supports changing the
* list of authorized principals for users.
*
* @return true if updating the list of authorized principals is
* @return true if updating the list of authorized principals is
* supported by this AuthorizationProvider.
*/
public abstract boolean isWritable();
/**
* Add a single authorized principal to use the named user.
*
......@@ -73,7 +73,7 @@ public abstract class AbstractAuthorizationProvider implements AuthorizationPoli
* @throws UnsupportedOperationException If this AuthorizationProvider cannot be updated.
*/
public abstract void addAuthorized(String username, String principal) throws UnsupportedOperationException;
/**
* Add a Collection of users authorized to use the named user.
*
......@@ -82,7 +82,7 @@ public abstract class AbstractAuthorizationProvider implements AuthorizationPoli
* @throws UnsupportedOperationException If this AuthorizationProvider cannot be updated.
*/
public abstract void addAuthorized(String username, Collection<String> principals) throws UnsupportedOperationException;
/**
* Set the users authorized to use the named user. All existing principals listed
* will be removed.
......@@ -99,11 +99,11 @@ public abstract class AbstractAuthorizationProvider implements AuthorizationPoli
* @return The short name of the Policy
*/
public abstract String name();
/**
* Returns a description of the Policy
*
* @return The description of the Policy.
*/
public abstract String description();
}
\ No newline at end of file
}
......@@ -11,14 +11,13 @@
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.JiveGlobals;
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.
......@@ -43,28 +42,48 @@ import org.jivesoftware.util.StringUtils;
*/
public class AuthorizationManager {
private static ArrayList<AuthorizationPolicy> authorizationPolicies = new ArrayList<AuthorizationPolicy>();
private static AuthorizationManager instance = new AuthorizationManager();
private static AuthorizationPolicy authorizationProvider;
static {
String className = JiveGlobals.getXMLProperty("provider.authorization.className");
if (className != null) {
try {
Class c_provider = ClassUtils.forName(className);
AuthorizationPolicy provider = (AuthorizationPolicy)(c_provider.newInstance());
Log.debug("AuthorizationManager: Loaded " + provider);
authorizationProvider = provider;
}
catch (Exception e) {
Log.error("Error loading AuthorizationProvider: " + className + "\n" + e);
String classList = JiveGlobals.getXMLProperty("provider.authorization.classList");
if (classList != null) {
StringTokenizer st = new StringTokenizer(classList, " ,\t\n\r\f");
while (st.hasMoreTokens()) {
String s_provider = st.nextToken();
try {
Class c_provider = ClassUtils.forName(s_provider);
AuthorizationPolicy provider =
(AuthorizationPolicy)(c_provider.newInstance());
Log.debug("AuthorizationManager: Loaded " + s_provider);
authorizationPolicies.add(provider);
}
catch (Exception e) {
Log.error("Error loading AuthorizationProvider: " + s_provider + "\n" + e);
}
}
}
if (authorizationProvider == null) {
if (authorizationPolicies.isEmpty()) {
Log.debug("No AuthorizationProvider's found. Loading DefaultAuthorizationPolicy");
// authorizationPolicies.add(new GSSAPIAuthorizationProvider());
}
}
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> getAuthorizationPolicies() {
return authorizationPolicies;
}
/**
* Returns a singleton AuthorizationManager instance.
......@@ -75,53 +94,19 @@ public class AuthorizationManager {
return instance;
}
private AuthorizationManager() {
}
/**
* Authorize the authenticated used to the requested username. This uses the
* GSSAPIAuthProvider if it is the specified provider.
* selected the selected AuthenticationProviders.
*
* @param username the username.
* @param principal the principal.
* @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;
}
}
// If the user is authorized, we want to check if the user is listed as a
// member of the <code>UserProvider</code>, and if not, add the user (if writable).
// 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);
public static boolean authorize(String authorId, String authenId) {
for (AuthorizationPolicy ap : authorizationPolicies) {
if (ap.authorize(authorId, authenId)) {
return true;
}
catch (UserAlreadyExistsException uaee) {
// Ignore.
}
}
return true;
return false;
}
}
/**
* $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.auth.UnauthorizedException;
/**
* Provider interface for authorization policy. Users that wish to integrate with
* their own authorization system must implement this class and then register
* the implementation 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;className&gt;com.foo.auth.CustomPolicyProvider&lt;/className&gt;
* &lt;/authorizationpolicy&gt;
* &lt;/provider&gt;</pre>
*
* @author Jay Kline
*/
public interface AuthorizationPolicyProvider {
/**
* Returns if the principal is explicity authorized to the JID, throws
* an UnauthorizedException otherwise
*
* @param username The username requested.
* @param principal The principal requesting the username.
* @throws UnauthorizedException
*/
public void authorize(String username, String principal) throws UnauthorizedException;
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision: $
* $Date: 2006-04-07 09:28:54 -0500 (Fri, 07 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.database.DbConnectionManager;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
/**
* Provider for authorization using the default storage database. Checks
* if the authenticated principal is in the user's list of authorized
* principals.
*
* @author Jay Kline
*/
public class DefaultAuthorizationProvider extends AbstractAuthorizationProvider
implements AuthorizationPolicy {
private static final String MATCH_AUTHORIZED =
"SELECT username FROM jiveSASLAuthorized WHERE username=? AND authorized=?";
private static final String GET_AUTHORIZED =
"SELECT authorized FROM jiveSASLAuthorized WHERE username=?";
private static final String INSERT_AUTHORIZED =
"INSERT into jiveSASLAuthorized (username,authorized) VALUES (?,?)";
private static final String DELETE_AUTHORIZED =
"DELETE FROM jiveSASLAuthorized WHERE username=? AND authorized=?";
private static final String DELETE_USER = "DELETE FROM jiveSASLAuthorized WHERE username=?";
/**
* 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) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(MATCH_AUTHORIZED);
pstmt.setString(1, username);
pstmt.setString(2, principal);
ResultSet rs = pstmt.executeQuery();
return rs.next();
}
catch (Exception e) {
return false;
}
finally {
try { if (pstmt != null) { pstmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
// not reachable
//return false;
}
/**
* Returns a String Collection of principals that are authorized to use
* the named user.
*
* @param username The username.
* @return A String Collection of principals that are authorized.
*/
public Collection<String> getAuthorized(String username) {
Connection con = null;
PreparedStatement pstmt = null;
Collection<String> authorized = new ArrayList<String>();
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(GET_AUTHORIZED);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
authorized.add(rs.getString("authorized"));
}
return authorized;
} catch (Exception e) {
return new ArrayList<String>();
}
finally {
try { if (pstmt != null) { pstmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
}
/**
* Returns true.
*
* @return true
*/
public boolean isWritable() {
return true;
}
/**
* Add a single authorized principal to use the named user.
*
* @param username The username.
* @param principal The principal authorized to use the named user.
* @throws UnsupportedOperationException If this AuthorizationProvider cannot be updated.
*/
public void addAuthorized(String username, String principal)
throws UnsupportedOperationException {
if (authorize(username, principal)) {
// Already exists
return;
}
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(INSERT_AUTHORIZED);
pstmt.setString(1, username);
pstmt.setString(2, principal);
pstmt.execute();
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
} finally {
try { if (pstmt != null) { pstmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
}
/**
* Add a Collection of users authorized to use the named user.
*
* @param username The username.
* @param principals The Collection of principals authorized to use the named user.
* @throws UnsupportedOperationException If this AuthorizationProvider cannot be updated.
*/
public void addAuthorized(String username, Collection<String> principals)
throws UnsupportedOperationException {
for (String principal : principals) {
addAuthorized(username, principal);
}
}
/**
* Set the users authorized to use the named user. All existing principals listed
* will be removed.
*
* @param username The username.
* @param principals The Collection of principals authorized to use the named user.
* @throws UnsupportedOperationException If this AuthorizationProvider cannot be updated.
*/
public void setAuthorized(String username, Collection<String> principals)
throws UnsupportedOperationException {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(DELETE_USER);
pstmt.setString(1, username);
pstmt.execute();
addAuthorized(username, principals);
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
finally {
try { if (pstmt != null) { pstmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
}
/**
* Returns the short name of the Policy
*
* @return The short name of the Policy
*/
public String name() {
return "Default Provider";
}
/**
* Returns a description of the Policy
*
* @return The description of the Policy.
*/
public String description() {
return "Provider for authorization using the default storage database.";
}
}
\ 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;
/**
* 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 Provider";
}
/**
* 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
......@@ -26,29 +26,29 @@ import java.util.Collection;
* the user's .k5login file. A traditional Unix Kerberos methodology. The
* location of this file can be configured in the <tt>openfire.xml</tt>
* file. An entry in that file would look like the following:
*
* <p/>
* <pre>
* &lt;unix&gt;
* &lt;k5login&gt; /home/{0}/.k5login &lt;/k5login&gt;
* &lt;/unix&gt;</pre>
*
* <p/>
* The string <tt>{0}</tt> will be replaced with the username.
*
* @author Jay Kline
*/
public class UnixK5LoginProvider extends AbstractAuthorizationProvider implements AuthorizationPolicy {
public class UnixK5LoginProvider extends AbstractAuthorizationProvider {
/**
* Returns true if the principal is explicity authorized to the JID
*
* @param username The username requested.
* @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 getAuthorized(username).contains(principal);
}
/**
* Returns a String Collection of principals that are authorized to use
* the named user.
......@@ -59,63 +59,64 @@ public class UnixK5LoginProvider extends AbstractAuthorizationProvider implement
public Collection<String> getAuthorized(String username) {
Collection<String> authorized = new ArrayList<String>();
try {
String filename = JiveGlobals.getXMLProperty("unix.k5login","/home/{0}/.k5login");
filename = filename.replace("{0}",username);
String filename = JiveGlobals.getXMLProperty("unix.k5login", "/home/{0}/.k5login");
filename = filename.replace("{0}", username);
File k5login = new File(filename);
FileInputStream fis = new FileInputStream(k5login);
DataInputStream dis = new DataInputStream(fis);
String line;
while ( (line = dis.readLine() ) != null) {
while ((line = dis.readLine()) != null) {
authorized.add(line);
}
} catch (IOException e) {
}
catch (IOException e) {
//??
}
return authorized;
return authorized;
}
/**
* Returns false, this implementation is not writeable.
* Returns false, this implementation is not writeable.
*
* @return False.
*/
public boolean isWritable() {
return false;
}
/**
* Always throws UnsupportedOperationException.
*
* @param username The username.
* @param username The username.
* @param principal The principal authorized to use the named user.
* @throws UnsupportedOperationException If this AuthorizationProvider cannot be updated.
*/
public void addAuthorized(String username, String principal) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Always throws UnsupportedOperationException.
*
* @param username The username.
* @param username The username.
* @param principals The Collection of principals authorized to use the named user.
*/
public void addAuthorized(String username, Collection<String> principals) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Always throws UnsupportedOperationException.
*
* @param username The username.
* @param username The username.
* @param principals The Collection of principals authorized to use the named user.
* @throws UnsupportedOperationException If this AuthorizationProvider cannot be updated.
*/
public void setAuthorized(String username, Collection<String> principals) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Returns the short name of the Policy
*
......@@ -124,7 +125,7 @@ public class UnixK5LoginProvider extends AbstractAuthorizationProvider implement
public String name() {
return "Unix .k5login";
}
/**
* Returns a description of the Policy
*
......@@ -133,4 +134,4 @@ public class UnixK5LoginProvider extends AbstractAuthorizationProvider implement
public String description() {
return "Checks if the authenticated principal is in the user's .k5login file. A traditional Unix Kerberos methodology.";
}
}
\ 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