Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
O
Openfire
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Openfire
Commits
5d9f2052
Commit
5d9f2052
authored
Aug 10, 2017
by
Greg Thomas
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix CR/LF endings
parent
a5ae728b
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
315 additions
and
315 deletions
+315
-315
AuthFactory.java
src/java/org/jivesoftware/openfire/auth/AuthFactory.java
+315
-315
No files found.
src/java/org/jivesoftware/openfire/auth/AuthFactory.java
View file @
5d9f2052
/*
/*
* Copyright (C) 2004-2008 Jive Software. All rights reserved.
* Copyright (C) 2004-2008 Jive Software. All rights reserved.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and
* limitations under the License.
* limitations under the License.
*/
*/
package
org
.
jivesoftware
.
openfire
.
auth
;
package
org
.
jivesoftware
.
openfire
.
auth
;
import
java.security.MessageDigest
;
import
java.security.MessageDigest
;
import
java.security.NoSuchAlgorithmException
;
import
java.security.NoSuchAlgorithmException
;
import
java.util.Map
;
import
java.util.Map
;
import
org.jivesoftware.openfire.lockout.LockOutManager
;
import
org.jivesoftware.openfire.lockout.LockOutManager
;
import
org.jivesoftware.openfire.user.UserNotFoundException
;
import
org.jivesoftware.openfire.user.UserNotFoundException
;
import
org.jivesoftware.util.Blowfish
;
import
org.jivesoftware.util.Blowfish
;
import
org.jivesoftware.util.ClassUtils
;
import
org.jivesoftware.util.ClassUtils
;
import
org.jivesoftware.util.JiveGlobals
;
import
org.jivesoftware.util.JiveGlobals
;
import
org.jivesoftware.util.LocaleUtils
;
import
org.jivesoftware.util.LocaleUtils
;
import
org.jivesoftware.util.PropertyEventDispatcher
;
import
org.jivesoftware.util.PropertyEventDispatcher
;
import
org.jivesoftware.util.PropertyEventListener
;
import
org.jivesoftware.util.PropertyEventListener
;
import
org.jivesoftware.util.StringUtils
;
import
org.jivesoftware.util.StringUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
/**
/**
* Pluggable authentication service. Users of Openfire that wish to change the AuthProvider
* Pluggable authentication service. Users of Openfire that wish to change the AuthProvider
* implementation used to authenticate users can set the <code>AuthProvider.className</code>
* implementation used to authenticate users can set the <code>AuthProvider.className</code>
* system property. For example, if you have configured Openfire to use LDAP for user information,
* system property. For example, if you have configured Openfire to use LDAP for user information,
* you'd want to send a custom implementation of AuthFactory to make LDAP auth queries.
* you'd want to send a custom implementation of AuthFactory to make LDAP auth queries.
* After changing the <code>AuthProvider.className</code> system property, you must restart your
* After changing the <code>AuthProvider.className</code> system property, you must restart your
* application server.
* application server.
*
*
* @author Matt Tucker
* @author Matt Tucker
*/
*/
public
class
AuthFactory
{
public
class
AuthFactory
{
private
static
final
Logger
Log
=
LoggerFactory
.
getLogger
(
AuthFactory
.
class
);
private
static
final
Logger
Log
=
LoggerFactory
.
getLogger
(
AuthFactory
.
class
);
private
static
AuthProvider
authProvider
=
null
;
private
static
AuthProvider
authProvider
=
null
;
private
static
MessageDigest
digest
;
private
static
MessageDigest
digest
;
private
static
final
Object
DIGEST_LOCK
=
new
Object
();
private
static
final
Object
DIGEST_LOCK
=
new
Object
();
private
static
Blowfish
cipher
=
null
;
private
static
Blowfish
cipher
=
null
;
static
{
static
{
// Create a message digest instance.
// Create a message digest instance.
try
{
try
{
digest
=
MessageDigest
.
getInstance
(
"SHA"
);
digest
=
MessageDigest
.
getInstance
(
"SHA"
);
}
}
catch
(
NoSuchAlgorithmException
e
)
{
catch
(
NoSuchAlgorithmException
e
)
{
Log
.
error
(
LocaleUtils
.
getLocalizedString
(
"admin.error"
),
e
);
Log
.
error
(
LocaleUtils
.
getLocalizedString
(
"admin.error"
),
e
);
}
}
// Load an auth provider.
// Load an auth provider.
initProvider
();
initProvider
();
// Detect when a new auth provider class is set
// Detect when a new auth provider class is set
PropertyEventListener
propListener
=
new
PropertyEventListener
()
{
PropertyEventListener
propListener
=
new
PropertyEventListener
()
{
@Override
@Override
public
void
propertySet
(
String
property
,
Map
params
)
{
public
void
propertySet
(
String
property
,
Map
params
)
{
if
(
"provider.auth.className"
.
equals
(
property
))
{
if
(
"provider.auth.className"
.
equals
(
property
))
{
initProvider
();
initProvider
();
}
}
}
}
@Override
@Override
public
void
propertyDeleted
(
String
property
,
Map
params
)
{
public
void
propertyDeleted
(
String
property
,
Map
params
)
{
//Ignore
//Ignore
}
}
@Override
@Override
public
void
xmlPropertySet
(
String
property
,
Map
params
)
{
public
void
xmlPropertySet
(
String
property
,
Map
params
)
{
//Ignore
//Ignore
}
}
@Override
@Override
public
void
xmlPropertyDeleted
(
String
property
,
Map
params
)
{
public
void
xmlPropertyDeleted
(
String
property
,
Map
params
)
{
//Ignore
//Ignore
}
}
};
};
PropertyEventDispatcher
.
addListener
(
propListener
);
PropertyEventDispatcher
.
addListener
(
propListener
);
}
}
private
static
void
initProvider
()
{
private
static
void
initProvider
()
{
// Convert XML based provider setup to Database based
// Convert XML based provider setup to Database based
JiveGlobals
.
migrateProperty
(
"provider.auth.className"
);
JiveGlobals
.
migrateProperty
(
"provider.auth.className"
);
String
className
=
JiveGlobals
.
getProperty
(
"provider.auth.className"
,
String
className
=
JiveGlobals
.
getProperty
(
"provider.auth.className"
,
"org.jivesoftware.openfire.auth.DefaultAuthProvider"
);
"org.jivesoftware.openfire.auth.DefaultAuthProvider"
);
// Check if we need to reset the auth provider class
// Check if we need to reset the auth provider class
if
(
authProvider
==
null
||
!
className
.
equals
(
authProvider
.
getClass
().
getName
()))
{
if
(
authProvider
==
null
||
!
className
.
equals
(
authProvider
.
getClass
().
getName
()))
{
try
{
try
{
Class
c
=
ClassUtils
.
forName
(
className
);
Class
c
=
ClassUtils
.
forName
(
className
);
authProvider
=
(
AuthProvider
)
c
.
newInstance
();
authProvider
=
(
AuthProvider
)
c
.
newInstance
();
}
}
catch
(
Exception
e
)
{
catch
(
Exception
e
)
{
Log
.
error
(
"Error loading auth provider: "
+
className
,
e
);
Log
.
error
(
"Error loading auth provider: "
+
className
,
e
);
authProvider
=
new
DefaultAuthProvider
();
authProvider
=
new
DefaultAuthProvider
();
}
}
}
}
}
}
/**
/**
* Returns the currently-installed AuthProvider. <b>Warning:</b> in virtually all
* Returns the currently-installed AuthProvider. <b>Warning:</b> in virtually all
* cases the auth provider should not be used directly. Instead, the appropriate
* cases the auth provider should not be used directly. Instead, the appropriate
* methods in AuthFactory should be called. Direct access to the auth provider is
* methods in AuthFactory should be called. Direct access to the auth provider is
* only provided for special-case logic.
* only provided for special-case logic.
*
*
* @return the current UserProvider.
* @return the current UserProvider.
* @deprecated Prefer using the corresponding factory method, rather than
* @deprecated Prefer using the corresponding factory method, rather than
* invoking methods on the provider directly
* invoking methods on the provider directly
*/
*/
public
static
AuthProvider
getAuthProvider
()
{
public
static
AuthProvider
getAuthProvider
()
{
return
authProvider
;
return
authProvider
;
}
}
/**
/**
* Returns whether the currently-installed AuthProvider is instance of a specific class.
* Returns whether the currently-installed AuthProvider is instance of a specific class.
* @param c the class to compare with
* @param c the class to compare with
* @return true - if the currently-installed AuthProvider is instance of c, false otherwise.
* @return true - if the currently-installed AuthProvider is instance of c, false otherwise.
*/
*/
public
static
boolean
isProviderInstanceOf
(
Class
<?>
c
)
{
public
static
boolean
isProviderInstanceOf
(
Class
<?>
c
)
{
return
c
.
isInstance
(
authProvider
);
return
c
.
isInstance
(
authProvider
);
}
}
/**
/**
* Indicates if the currently-installed AuthProvider is the HybridAuthProvider supporting a specific class.
* Indicates if the currently-installed AuthProvider is the HybridAuthProvider supporting a specific class.
*
*
* @param clazz the class to check
* @param clazz the class to check
* @return {@code true} if the currently-installed AuthProvider is a HybridAuthProvider that supports an instance of clazz, otherwise {@code false}.
* @return {@code true} if the currently-installed AuthProvider is a HybridAuthProvider that supports an instance of clazz, otherwise {@code false}.
*/
*/
public
static
boolean
isProviderHybridInstanceOf
(
Class
<?
extends
AuthProvider
>
clazz
)
{
public
static
boolean
isProviderHybridInstanceOf
(
Class
<?
extends
AuthProvider
>
clazz
)
{
return
authProvider
instanceof
HybridAuthProvider
&&
return
authProvider
instanceof
HybridAuthProvider
&&
((
HybridAuthProvider
)
authProvider
).
isProvider
(
clazz
);
((
HybridAuthProvider
)
authProvider
).
isProvider
(
clazz
);
}
}
/**
/**
* Returns true if the currently installed {@link AuthProvider} supports password
* Returns true if the currently installed {@link AuthProvider} supports password
* retrieval. Certain implementation utilize password hashes and other authentication
* retrieval. Certain implementation utilize password hashes and other authentication
* mechanisms that do not require the original password.
* mechanisms that do not require the original password.
*
*
* @return true if plain password retrieval is supported.
* @return true if plain password retrieval is supported.
*/
*/
public
static
boolean
supportsPasswordRetrieval
()
{
public
static
boolean
supportsPasswordRetrieval
()
{
return
authProvider
.
supportsPasswordRetrieval
();
return
authProvider
.
supportsPasswordRetrieval
();
}
}
/**
/**
* Returns the user's password. This method will throw an UnsupportedOperationException
* Returns the user's password. This method will throw an UnsupportedOperationException
* if this operation is not supported by the backend user store.
* if this operation is not supported by the backend user store.
*
*
* @param username the username of the user.
* @param username the username of the user.
* @return the user's password.
* @return the user's password.
* @throws UserNotFoundException if the given user could not be found.
* @throws UserNotFoundException if the given user could not be found.
* @throws UnsupportedOperationException if the provider does not
* @throws UnsupportedOperationException if the provider does not
* support the operation (this is an optional operation).
* support the operation (this is an optional operation).
*/
*/
public
static
String
getPassword
(
String
username
)
throws
UserNotFoundException
,
public
static
String
getPassword
(
String
username
)
throws
UserNotFoundException
,
UnsupportedOperationException
{
UnsupportedOperationException
{
return
authProvider
.
getPassword
(
username
.
toLowerCase
());
return
authProvider
.
getPassword
(
username
.
toLowerCase
());
}
}
/**
/**
* Sets the users's password. This method should throw an UnsupportedOperationException
* Sets the users's password. This method should throw an UnsupportedOperationException
* if this operation is not supported by the backend user store.
* if this operation is not supported by the backend user store.
*
*
* @param username the username of the user.
* @param username the username of the user.
* @param password the new plaintext password for the user.
* @param password the new plaintext password for the user.
* @throws UserNotFoundException if the given user could not be loaded.
* @throws UserNotFoundException if the given user could not be loaded.
* @throws UnsupportedOperationException if the provider does not
* @throws UnsupportedOperationException if the provider does not
* support the operation (this is an optional operation).
* support the operation (this is an optional operation).
*/
*/
public
static
void
setPassword
(
String
username
,
String
password
)
throws
UserNotFoundException
,
public
static
void
setPassword
(
String
username
,
String
password
)
throws
UserNotFoundException
,
UnsupportedOperationException
,
ConnectionException
,
InternalUnauthenticatedException
{
UnsupportedOperationException
,
ConnectionException
,
InternalUnauthenticatedException
{
authProvider
.
setPassword
(
username
,
password
);
authProvider
.
setPassword
(
username
,
password
);
}
}
/**
/**
* Authenticates a user with a username and plain text password and returns and
* Authenticates a user with a username and plain text password and returns and
* AuthToken. If the username and password do not match the record of
* AuthToken. If the username and password do not match the record of
* any user in the system, this method throws an UnauthorizedException.
* any user in the system, this method throws an UnauthorizedException.
*
*
* @param username the username.
* @param username the username.
* @param password the password.
* @param password the password.
* @return an AuthToken token if the username and password are correct.
* @return an AuthToken token if the username and password are correct.
* @throws UnauthorizedException if the username and password do not match any existing user
* @throws UnauthorizedException if the username and password do not match any existing user
* or the account is locked out.
* or the account is locked out.
*/
*/
public
static
AuthToken
authenticate
(
String
username
,
String
password
)
public
static
AuthToken
authenticate
(
String
username
,
String
password
)
throws
UnauthorizedException
,
ConnectionException
,
InternalUnauthenticatedException
{
throws
UnauthorizedException
,
ConnectionException
,
InternalUnauthenticatedException
{
if
(
LockOutManager
.
getInstance
().
isAccountDisabled
(
username
))
{
if
(
LockOutManager
.
getInstance
().
isAccountDisabled
(
username
))
{
LockOutManager
.
getInstance
().
recordFailedLogin
(
username
);
LockOutManager
.
getInstance
().
recordFailedLogin
(
username
);
throw
new
UnauthorizedException
();
throw
new
UnauthorizedException
();
}
}
authProvider
.
authenticate
(
username
,
password
);
authProvider
.
authenticate
(
username
,
password
);
return
new
AuthToken
(
username
);
return
new
AuthToken
(
username
);
}
}
/**
/**
* Returns a digest given a token and password, according to JEP-0078.
* Returns a digest given a token and password, according to JEP-0078.
*
*
* @param token the token used in the digest.
* @param token the token used in the digest.
* @param password the plain-text password to be digested.
* @param password the plain-text password to be digested.
* @return the digested result as a hex string.
* @return the digested result as a hex string.
*/
*/
public
static
String
createDigest
(
String
token
,
String
password
)
{
public
static
String
createDigest
(
String
token
,
String
password
)
{
synchronized
(
DIGEST_LOCK
)
{
synchronized
(
DIGEST_LOCK
)
{
digest
.
update
(
token
.
getBytes
());
digest
.
update
(
token
.
getBytes
());
return
StringUtils
.
encodeHex
(
digest
.
digest
(
password
.
getBytes
()));
return
StringUtils
.
encodeHex
(
digest
.
digest
(
password
.
getBytes
()));
}
}
}
}
/**
/**
* Returns an encrypted version of the plain-text password. Encryption is performed
* Returns an encrypted version of the plain-text password. Encryption is performed
* using the Blowfish algorithm. The encryption key is stored as the Jive property
* using the Blowfish algorithm. The encryption key is stored as the Jive property
* "passwordKey". If the key is not present, it will be automatically generated.
* "passwordKey". If the key is not present, it will be automatically generated.
*
*
* @param password the plain-text password.
* @param password the plain-text password.
* @return the encrypted password.
* @return the encrypted password.
* @throws UnsupportedOperationException if encryption/decryption is not possible;
* @throws UnsupportedOperationException if encryption/decryption is not possible;
* for example, during setup mode.
* for example, during setup mode.
*/
*/
public
static
String
encryptPassword
(
String
password
)
{
public
static
String
encryptPassword
(
String
password
)
{
if
(
password
==
null
)
{
if
(
password
==
null
)
{
return
null
;
return
null
;
}
}
Blowfish
cipher
=
getCipher
();
Blowfish
cipher
=
getCipher
();
if
(
cipher
==
null
)
{
if
(
cipher
==
null
)
{
throw
new
UnsupportedOperationException
();
throw
new
UnsupportedOperationException
();
}
}
return
cipher
.
encryptString
(
password
);
return
cipher
.
encryptString
(
password
);
}
}
/**
/**
* Returns a decrypted version of the encrypted password. Encryption is performed
* Returns a decrypted version of the encrypted password. Encryption is performed
* using the Blowfish algorithm. The encryption key is stored as the Jive property
* using the Blowfish algorithm. The encryption key is stored as the Jive property
* "passwordKey". If the key is not present, it will be automatically generated.
* "passwordKey". If the key is not present, it will be automatically generated.
*
*
* @param encryptedPassword the encrypted password.
* @param encryptedPassword the encrypted password.
* @return the encrypted password.
* @return the encrypted password.
* @throws UnsupportedOperationException if encryption/decryption is not possible;
* @throws UnsupportedOperationException if encryption/decryption is not possible;
* for example, during setup mode.
* for example, during setup mode.
*/
*/
public
static
String
decryptPassword
(
String
encryptedPassword
)
{
public
static
String
decryptPassword
(
String
encryptedPassword
)
{
if
(
encryptedPassword
==
null
)
{
if
(
encryptedPassword
==
null
)
{
return
null
;
return
null
;
}
}
Blowfish
cipher
=
getCipher
();
Blowfish
cipher
=
getCipher
();
if
(
cipher
==
null
)
{
if
(
cipher
==
null
)
{
throw
new
UnsupportedOperationException
();
throw
new
UnsupportedOperationException
();
}
}
return
cipher
.
decryptString
(
encryptedPassword
);
return
cipher
.
decryptString
(
encryptedPassword
);
}
}
/**
/**
* Returns a Blowfish cipher that can be used for encrypting and decrypting passwords.
* Returns a Blowfish cipher that can be used for encrypting and decrypting passwords.
* The encryption key is stored as the Jive property "passwordKey". If it's not present,
* The encryption key is stored as the Jive property "passwordKey". If it's not present,
* it will be automatically generated.
* it will be automatically generated.
*
*
* @return the Blowfish cipher, or <tt>null</tt> if Openfire is not able to create a Cipher;
* @return the Blowfish cipher, or <tt>null</tt> if Openfire is not able to create a Cipher;
* for example, during setup mode.
* for example, during setup mode.
*/
*/
private
static
synchronized
Blowfish
getCipher
()
{
private
static
synchronized
Blowfish
getCipher
()
{
if
(
cipher
!=
null
)
{
if
(
cipher
!=
null
)
{
return
cipher
;
return
cipher
;
}
}
// Get the password key, stored as a database property. Obviously,
// Get the password key, stored as a database property. Obviously,
// protecting your database is critical for making the
// protecting your database is critical for making the
// encryption fully secure.
// encryption fully secure.
String
keyString
;
String
keyString
;
try
{
try
{
keyString
=
JiveGlobals
.
getProperty
(
"passwordKey"
);
keyString
=
JiveGlobals
.
getProperty
(
"passwordKey"
);
if
(
keyString
==
null
)
{
if
(
keyString
==
null
)
{
keyString
=
StringUtils
.
randomString
(
15
);
keyString
=
StringUtils
.
randomString
(
15
);
JiveGlobals
.
setProperty
(
"passwordKey"
,
keyString
);
JiveGlobals
.
setProperty
(
"passwordKey"
,
keyString
);
// Check to make sure that setting the property worked. It won't work,
// Check to make sure that setting the property worked. It won't work,
// for example, when in setup mode.
// for example, when in setup mode.
if
(!
keyString
.
equals
(
JiveGlobals
.
getProperty
(
"passwordKey"
)))
{
if
(!
keyString
.
equals
(
JiveGlobals
.
getProperty
(
"passwordKey"
)))
{
return
null
;
return
null
;
}
}
}
}
cipher
=
new
Blowfish
(
keyString
);
cipher
=
new
Blowfish
(
keyString
);
}
}
catch
(
Exception
e
)
{
catch
(
Exception
e
)
{
Log
.
error
(
e
.
getMessage
(),
e
);
Log
.
error
(
e
.
getMessage
(),
e
);
}
}
return
cipher
;
return
cipher
;
}
}
public
static
boolean
supportsScram
()
{
public
static
boolean
supportsScram
()
{
// TODO Auto-generated method stub
// TODO Auto-generated method stub
return
authProvider
.
isScramSupported
();
return
authProvider
.
isScramSupported
();
}
}
public
static
String
getSalt
(
String
username
)
throws
UnsupportedOperationException
,
UserNotFoundException
{
public
static
String
getSalt
(
String
username
)
throws
UnsupportedOperationException
,
UserNotFoundException
{
return
authProvider
.
getSalt
(
username
);
return
authProvider
.
getSalt
(
username
);
}
}
public
static
int
getIterations
(
String
username
)
throws
UnsupportedOperationException
,
UserNotFoundException
{
public
static
int
getIterations
(
String
username
)
throws
UnsupportedOperationException
,
UserNotFoundException
{
return
authProvider
.
getIterations
(
username
);
return
authProvider
.
getIterations
(
username
);
}
}
public
static
String
getServerKey
(
String
username
)
throws
UnsupportedOperationException
,
UserNotFoundException
{
public
static
String
getServerKey
(
String
username
)
throws
UnsupportedOperationException
,
UserNotFoundException
{
return
authProvider
.
getServerKey
(
username
);
return
authProvider
.
getServerKey
(
username
);
}
}
public
static
String
getStoredKey
(
String
username
)
throws
UnsupportedOperationException
,
UserNotFoundException
{
public
static
String
getStoredKey
(
String
username
)
throws
UnsupportedOperationException
,
UserNotFoundException
{
return
authProvider
.
getStoredKey
(
username
);
return
authProvider
.
getStoredKey
(
username
);
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment