mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-09 15:05:44 +01:00
replace scm-manager 1.x security api with apache shiro and use PasswordService for stronger password hashes
This commit is contained in:
@@ -35,6 +35,7 @@ package sonia.scm.group;
|
|||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
@@ -156,6 +157,18 @@ public final class GroupNames implements Serializable, Iterable<String>
|
|||||||
return collection.iterator();
|
return collection.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return Joiner.on(", ").join(collection);
|
||||||
|
}
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
//~--- get methods ----------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -172,5 +185,5 @@ public final class GroupNames implements Serializable, Iterable<String>
|
|||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
private Collection<String> collection;
|
private final Collection<String> collection;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.security;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public class EncryptionException extends RuntimeException
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private static final long serialVersionUID = -3733681356044140444L;
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public EncryptionException()
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param message
|
|
||||||
*/
|
|
||||||
public EncryptionException(String message)
|
|
||||||
{
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param cause
|
|
||||||
*/
|
|
||||||
public EncryptionException(Throwable cause)
|
|
||||||
{
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param message
|
|
||||||
* @param cause
|
|
||||||
*/
|
|
||||||
public EncryptionException(String message, Throwable cause)
|
|
||||||
{
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.security;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public interface EncryptionHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String encrypt(String value);
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer. 2. Redistributions in
|
|
||||||
* binary form must reproduce the above copyright notice, this list of
|
|
||||||
* conditions and the following disclaimer in the documentation and/or other
|
|
||||||
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
|
||||||
* nor the names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import org.apache.shiro.authc.AuthenticationException;
|
|
||||||
import org.apache.shiro.authc.AuthenticationToken;
|
|
||||||
|
|
||||||
import sonia.scm.web.security.AuthenticationResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Login attempt handler.
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
* @since 1.34
|
|
||||||
*/
|
|
||||||
public interface LoginAttemptHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called before the authentication procedure is invoked.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param token authentication token
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException
|
|
||||||
*/
|
|
||||||
public void beforeAuthentication(AuthenticationToken token)
|
|
||||||
throws AuthenticationException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle successful authentication.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param token authentication token
|
|
||||||
* @param result successful authentication result
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException
|
|
||||||
*/
|
|
||||||
public void onSuccessfulAuthentication(AuthenticationToken token,
|
|
||||||
AuthenticationResult result)
|
|
||||||
throws AuthenticationException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle unsuccessful authentication.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param token authentication token
|
|
||||||
* @param result unsuccessful authentication result
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException
|
|
||||||
*/
|
|
||||||
public void onUnsuccessfulAuthentication(AuthenticationToken token,
|
|
||||||
AuthenticationResult result)
|
|
||||||
throws AuthenticationException;
|
|
||||||
}
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import sonia.scm.util.AssertUtil;
|
|
||||||
import sonia.scm.util.Util;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public class MessageDigestEncryptionHandler implements EncryptionHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
public static final String DEFAULT_DIGEST = "SHA-1";
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public MessageDigestEncryptionHandler()
|
|
||||||
{
|
|
||||||
this.digest = DEFAULT_DIGEST;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param digest
|
|
||||||
*/
|
|
||||||
public MessageDigestEncryptionHandler(String digest)
|
|
||||||
{
|
|
||||||
this.digest = digest;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String encrypt(String value)
|
|
||||||
{
|
|
||||||
String result = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AssertUtil.assertIsNotEmpty(value);
|
|
||||||
|
|
||||||
MessageDigest messageDigest = MessageDigest.getInstance(digest);
|
|
||||||
|
|
||||||
result = encrypt(messageDigest, value);
|
|
||||||
}
|
|
||||||
catch (NoSuchAlgorithmException ex)
|
|
||||||
{
|
|
||||||
throw new EncryptionException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getDigest()
|
|
||||||
{
|
|
||||||
return digest;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param messageDigest
|
|
||||||
* @param value
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private String encrypt(MessageDigest messageDigest, String value)
|
|
||||||
{
|
|
||||||
messageDigest.reset();
|
|
||||||
messageDigest.update(value.getBytes());
|
|
||||||
|
|
||||||
return Util.toString(messageDigest.digest());
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String digest;
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import sonia.scm.PasswordAware;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a plain text password matches against a encrypted one and updates
|
|
||||||
* password objects.
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
* @since 1.13
|
|
||||||
*/
|
|
||||||
public interface PasswordHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the given password
|
|
||||||
* is the same as store in the password object.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param passwordAware object that holds the encrypted password
|
|
||||||
* @param password plain text password to check
|
|
||||||
*
|
|
||||||
* @return true if the password matches the encrypted one
|
|
||||||
*/
|
|
||||||
public boolean matches(PasswordAware passwordAware, String password);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the password of the given password object.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param passwordAware object to update
|
|
||||||
* @param password plain text password
|
|
||||||
*/
|
|
||||||
public void updatePassword(PasswordAware passwordAware, String password);
|
|
||||||
}
|
|
||||||
@@ -73,6 +73,18 @@ public final class HttpUtil
|
|||||||
/** Field description */
|
/** Field description */
|
||||||
public static final String ENCODING = "UTF-8";
|
public static final String ENCODING = "UTF-8";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* authorization header
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
public static final String HEADER_AUTHORIZATION = "Authorization";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic authorization scheme
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
public static final String AUTHORIZATION_SCHEME_BASIC = "Basic";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* location header
|
* location header
|
||||||
* @since 1.43
|
* @since 1.43
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.web.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
import sonia.scm.event.ScmEventBus;
|
|
||||||
import sonia.scm.user.User;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract base class for {@link AuthenticationManager} implementations. This
|
|
||||||
* class implements the listener methods of the {@link AuthenticationManager}
|
|
||||||
* interface.
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public abstract class AbstractAuthenticationManager
|
|
||||||
implements AuthenticationManager
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Send a {@link AuthenticationEvent} to the {@link ScmEventBus}.
|
|
||||||
*
|
|
||||||
* @param user successful authenticated user
|
|
||||||
*/
|
|
||||||
protected void fireAuthenticationEvent(User user)
|
|
||||||
{
|
|
||||||
ScmEventBus.getInstance().post(new AuthenticationEvent(user));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.web.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
|
||||||
|
|
||||||
import sonia.scm.event.Event;
|
|
||||||
import sonia.scm.user.User;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The authentication event is called after a successful authentication.
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
* @since 1.27
|
|
||||||
*/
|
|
||||||
@Event
|
|
||||||
public class AuthenticationEvent
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new authentication event.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user successful authenticated user
|
|
||||||
*/
|
|
||||||
public AuthenticationEvent(User user)
|
|
||||||
{
|
|
||||||
this.user = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param obj
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final AuthenticationEvent other = (AuthenticationEvent) obj;
|
|
||||||
|
|
||||||
return Objects.equal(user, other.user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Objects.hashCode(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
|
|
||||||
// J+
|
|
||||||
return Objects.toStringHelper(this).add("user", user).toString();
|
|
||||||
|
|
||||||
// J+
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the successful authenticated user.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return successful authenticated user
|
|
||||||
*/
|
|
||||||
public User getUser()
|
|
||||||
{
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** successful authenticated user */
|
|
||||||
private User user;
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.web.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import sonia.scm.Initable;
|
|
||||||
import sonia.scm.TypedObject;
|
|
||||||
import sonia.scm.plugin.ExtensionPoint;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
@ExtensionPoint
|
|
||||||
public interface AuthenticationHandler extends Initable, Closeable, TypedObject
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @param username
|
|
||||||
* @param password
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public AuthenticationResult authenticate(HttpServletRequest request,
|
|
||||||
HttpServletResponse response, String username, String password);
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.web.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import sonia.scm.Initable;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public interface AuthenticationManager
|
|
||||||
extends Initable, Closeable
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @param username
|
|
||||||
* @param password
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public AuthenticationResult authenticate(HttpServletRequest request,
|
|
||||||
HttpServletResponse response, String username, String password);
|
|
||||||
}
|
|
||||||
@@ -1,231 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.web.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import sonia.scm.user.User;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public class AuthenticationResult implements Serializable
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
public static final AuthenticationResult NOT_FOUND =
|
|
||||||
new AuthenticationResult(AuthenticationState.NOT_FOUND);
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
public static final AuthenticationResult FAILED =
|
|
||||||
new AuthenticationResult(AuthenticationState.FAILED);
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private static final long serialVersionUID = -1318200822398893598L;
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param state
|
|
||||||
*/
|
|
||||||
public AuthenticationResult(AuthenticationState state)
|
|
||||||
{
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
*/
|
|
||||||
public AuthenticationResult(User user)
|
|
||||||
{
|
|
||||||
this.user = user;
|
|
||||||
this.state = AuthenticationState.SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param state
|
|
||||||
*/
|
|
||||||
public AuthenticationResult(User user, AuthenticationState state)
|
|
||||||
{
|
|
||||||
this.user = user;
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param groups
|
|
||||||
*/
|
|
||||||
public AuthenticationResult(User user, Collection<String> groups)
|
|
||||||
{
|
|
||||||
this.user = user;
|
|
||||||
this.groups = groups;
|
|
||||||
this.state = AuthenticationState.SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param groups
|
|
||||||
* @param state
|
|
||||||
*/
|
|
||||||
public AuthenticationResult(User user, Collection<String> groups,
|
|
||||||
AuthenticationState state)
|
|
||||||
{
|
|
||||||
this.user = user;
|
|
||||||
this.groups = groups;
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
StringBuilder out = new StringBuilder("user: ");
|
|
||||||
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
out.append(user.getName());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
out.append("null");
|
|
||||||
}
|
|
||||||
|
|
||||||
return out.append(", state: ").append(state.toString()).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Collection<String> getGroups()
|
|
||||||
{
|
|
||||||
return groups;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public AuthenticationState getState()
|
|
||||||
{
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public User getUser()
|
|
||||||
{
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean isCacheable()
|
|
||||||
{
|
|
||||||
return cacheable;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- set methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param cacheable
|
|
||||||
*/
|
|
||||||
public void setCacheable(boolean cacheable)
|
|
||||||
{
|
|
||||||
this.cacheable = cacheable;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private boolean cacheable = true;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private Collection<String> groups;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private AuthenticationState state;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private User user;
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.web.security;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public enum AuthenticationState
|
|
||||||
{
|
|
||||||
SUCCESS(true), NOT_FOUND(false), FAILED(false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param successfully
|
|
||||||
*/
|
|
||||||
private AuthenticationState(boolean successfully)
|
|
||||||
{
|
|
||||||
this.successfully = successfully;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean isSuccessfully()
|
|
||||||
{
|
|
||||||
return successfully;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private boolean successfully = false;
|
|
||||||
}
|
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
<name>scmadmin</name>
|
<name>scmadmin</name>
|
||||||
<displayName>SCM Administrator</displayName>
|
<displayName>SCM Administrator</displayName>
|
||||||
<mail>scm-admin@scm-manager.org</mail>
|
<mail>scm-admin@scm-manager.org</mail>
|
||||||
<password>ff8f5c593a01f9fcd3ed48b09a4b013e8d8f3be7</password>
|
<password>$shiro1$SHA-512$8192$$yrNahBVDa4Gz+y5gat4msdjyvjtHlVE+N5nTl4WIDhtBFwhSIib13mKJt1sWmVqgHDWi3VwX7fkdkJ2+WToTbw==</password>
|
||||||
<admin>true</admin>
|
<admin>true</admin>
|
||||||
<type>xml</type>
|
<type>xml</type>
|
||||||
</users>
|
</users>
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ package sonia.scm.web;
|
|||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
@@ -51,13 +52,17 @@ import sonia.scm.repository.HgRepositoryHandler;
|
|||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
import sonia.scm.repository.RepositoryProvider;
|
import sonia.scm.repository.RepositoryProvider;
|
||||||
import sonia.scm.repository.RepositoryRequestListenerUtil;
|
import sonia.scm.repository.RepositoryRequestListenerUtil;
|
||||||
|
import sonia.scm.security.CipherUtil;
|
||||||
import sonia.scm.util.AssertUtil;
|
import sonia.scm.util.AssertUtil;
|
||||||
|
import sonia.scm.util.HttpUtil;
|
||||||
import sonia.scm.web.cgi.CGIExecutor;
|
import sonia.scm.web.cgi.CGIExecutor;
|
||||||
import sonia.scm.web.cgi.CGIExecutorFactory;
|
import sonia.scm.web.cgi.CGIExecutorFactory;
|
||||||
import sonia.scm.web.cgi.EnvList;
|
import sonia.scm.web.cgi.EnvList;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
|
import com.sun.jersey.core.util.Base64;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -86,6 +91,9 @@ public class HgCGIServlet extends HttpServlet
|
|||||||
/** Field description */
|
/** Field description */
|
||||||
public static final String ENV_SESSION_PREFIX = "SCM_";
|
public static final String ENV_SESSION_PREFIX = "SCM_";
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private static final String SCM_CREDENTIALS = "SCM_CREDENTIALS";
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
private static final long serialVersionUID = -3492811300905099810L;
|
private static final long serialVersionUID = -3492811300905099810L;
|
||||||
|
|
||||||
@@ -183,6 +191,39 @@ public class HgCGIServlet extends HttpServlet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param env
|
||||||
|
* @param request
|
||||||
|
*/
|
||||||
|
private void addCredentials(EnvList env, HttpServletRequest request)
|
||||||
|
{
|
||||||
|
String authorization = request.getHeader(HttpUtil.HEADER_AUTHORIZATION);
|
||||||
|
|
||||||
|
if (!Strings.isNullOrEmpty(authorization))
|
||||||
|
{
|
||||||
|
if (authorization.startsWith(HttpUtil.AUTHORIZATION_SCHEME_BASIC))
|
||||||
|
{
|
||||||
|
String encodedUserInfo =
|
||||||
|
authorization.substring(
|
||||||
|
HttpUtil.AUTHORIZATION_SCHEME_BASIC.length()).trim();
|
||||||
|
String userInfo = Base64.base64Decode(encodedUserInfo);
|
||||||
|
|
||||||
|
env.set(SCM_CREDENTIALS, CipherUtil.getInstance().encode(userInfo));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.warn("unknow authentication scheme used");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.trace("no authorization header found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
@@ -259,6 +300,7 @@ public class HgCGIServlet extends HttpServlet
|
|||||||
executor.getEnvironment().set(ENV_REPOSITORY_NAME, name);
|
executor.getEnvironment().set(ENV_REPOSITORY_NAME, name);
|
||||||
executor.getEnvironment().set(ENV_REPOSITORY_PATH,
|
executor.getEnvironment().set(ENV_REPOSITORY_PATH,
|
||||||
directory.getAbsolutePath());
|
directory.getAbsolutePath());
|
||||||
|
|
||||||
// add hook environment
|
// add hook environment
|
||||||
//J-
|
//J-
|
||||||
HgEnvironment.prepareEnvironment(
|
HgEnvironment.prepareEnvironment(
|
||||||
@@ -269,6 +311,9 @@ public class HgCGIServlet extends HttpServlet
|
|||||||
);
|
);
|
||||||
//J+
|
//J+
|
||||||
|
|
||||||
|
addCredentials(executor.getEnvironment(), request);
|
||||||
|
|
||||||
|
// unused ???
|
||||||
HttpSession session = request.getSession();
|
HttpSession session = request.getSession();
|
||||||
|
|
||||||
if (session != null)
|
if (session != null)
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ import sonia.scm.store.StoreFactory;
|
|||||||
import sonia.scm.upgrade.UpgradeManager;
|
import sonia.scm.upgrade.UpgradeManager;
|
||||||
import sonia.scm.user.UserManager;
|
import sonia.scm.user.UserManager;
|
||||||
import sonia.scm.util.IOUtil;
|
import sonia.scm.util.IOUtil;
|
||||||
import sonia.scm.web.security.AuthenticationManager;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
@@ -100,9 +99,6 @@ public class ScmContextListener extends GuiceServletContextListener
|
|||||||
// close RepositoryManager
|
// close RepositoryManager
|
||||||
IOUtil.close(globalInjector.getInstance(RepositoryManager.class));
|
IOUtil.close(globalInjector.getInstance(RepositoryManager.class));
|
||||||
|
|
||||||
// close Authenticator
|
|
||||||
IOUtil.close(globalInjector.getInstance(AuthenticationManager.class));
|
|
||||||
|
|
||||||
// close GroupManager
|
// close GroupManager
|
||||||
IOUtil.close(globalInjector.getInstance(GroupManager.class));
|
IOUtil.close(globalInjector.getInstance(GroupManager.class));
|
||||||
|
|
||||||
|
|||||||
@@ -37,9 +37,12 @@ package sonia.scm;
|
|||||||
|
|
||||||
import com.google.inject.name.Names;
|
import com.google.inject.name.Names;
|
||||||
|
|
||||||
|
import org.apache.shiro.authc.credential.DefaultPasswordService;
|
||||||
|
import org.apache.shiro.authc.credential.PasswordService;
|
||||||
|
import org.apache.shiro.crypto.hash.DefaultHashService;
|
||||||
import org.apache.shiro.guice.web.ShiroWebModule;
|
import org.apache.shiro.guice.web.ShiroWebModule;
|
||||||
|
|
||||||
import sonia.scm.security.ScmRealm;
|
import sonia.scm.security.DefaultRealm;
|
||||||
|
|
||||||
import static org.apache.shiro.guice.web.ShiroWebModule.ROLES;
|
import static org.apache.shiro.guice.web.ShiroWebModule.ROLES;
|
||||||
|
|
||||||
@@ -54,6 +57,11 @@ import javax.servlet.ServletContext;
|
|||||||
public class ScmSecurityModule extends ShiroWebModule
|
public class ScmSecurityModule extends ShiroWebModule
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private static final int ITERATIONS = 8192;
|
||||||
|
|
||||||
|
//~--- constructors ---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs ...
|
* Constructs ...
|
||||||
*
|
*
|
||||||
@@ -75,9 +83,13 @@ public class ScmSecurityModule extends ShiroWebModule
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected void configureShiroWeb()
|
protected void configureShiroWeb()
|
||||||
{
|
{
|
||||||
|
bind(PasswordService.class).toInstance(createPasswordService());
|
||||||
|
|
||||||
|
// expose password service to global injector
|
||||||
|
expose(PasswordService.class);
|
||||||
|
|
||||||
// bind realm
|
// bind realm
|
||||||
bindRealm().to(ScmRealm.class);
|
bindRealm().to(DefaultRealm.class);
|
||||||
|
|
||||||
// bind constant
|
// bind constant
|
||||||
bindConstant().annotatedWith(Names.named("shiro.loginUrl")).to(
|
bindConstant().annotatedWith(Names.named("shiro.loginUrl")).to(
|
||||||
@@ -86,4 +98,21 @@ public class ScmSecurityModule extends ShiroWebModule
|
|||||||
// disable access to mustache resources
|
// disable access to mustache resources
|
||||||
addFilterChain("/**.mustache", config(ROLES, "nobody"));
|
addFilterChain("/**.mustache", config(ROLES, "nobody"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link PasswordService} with a smaller size of iteration, because
|
||||||
|
* large iterations will slow down subversion.
|
||||||
|
*
|
||||||
|
* @return instance of {@link PasswordService}
|
||||||
|
*/
|
||||||
|
private PasswordService createPasswordService()
|
||||||
|
{
|
||||||
|
DefaultPasswordService passwordService = new DefaultPasswordService();
|
||||||
|
DefaultHashService hashService = new DefaultHashService();
|
||||||
|
|
||||||
|
hashService.setHashIterations(ITERATIONS);
|
||||||
|
passwordService.setHashService(hashService);
|
||||||
|
|
||||||
|
return passwordService;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,13 +88,9 @@ import sonia.scm.resources.ResourceManager;
|
|||||||
import sonia.scm.resources.ScriptResourceServlet;
|
import sonia.scm.resources.ScriptResourceServlet;
|
||||||
import sonia.scm.security.CipherHandler;
|
import sonia.scm.security.CipherHandler;
|
||||||
import sonia.scm.security.CipherUtil;
|
import sonia.scm.security.CipherUtil;
|
||||||
import sonia.scm.security.ConfigurableLoginAttemptHandler;
|
|
||||||
import sonia.scm.security.DefaultKeyGenerator;
|
import sonia.scm.security.DefaultKeyGenerator;
|
||||||
import sonia.scm.security.DefaultSecuritySystem;
|
import sonia.scm.security.DefaultSecuritySystem;
|
||||||
import sonia.scm.security.EncryptionHandler;
|
|
||||||
import sonia.scm.security.KeyGenerator;
|
import sonia.scm.security.KeyGenerator;
|
||||||
import sonia.scm.security.LoginAttemptHandler;
|
|
||||||
import sonia.scm.security.MessageDigestEncryptionHandler;
|
|
||||||
import sonia.scm.security.RepositoryPermissionResolver;
|
import sonia.scm.security.RepositoryPermissionResolver;
|
||||||
import sonia.scm.security.SecuritySystem;
|
import sonia.scm.security.SecuritySystem;
|
||||||
import sonia.scm.store.BlobStoreFactory;
|
import sonia.scm.store.BlobStoreFactory;
|
||||||
@@ -127,8 +123,6 @@ import sonia.scm.web.filter.AutoLoginFilter;
|
|||||||
import sonia.scm.web.filter.LoggingFilter;
|
import sonia.scm.web.filter.LoggingFilter;
|
||||||
import sonia.scm.web.security.AdministrationContext;
|
import sonia.scm.web.security.AdministrationContext;
|
||||||
import sonia.scm.web.security.ApiBasicAuthenticationFilter;
|
import sonia.scm.web.security.ApiBasicAuthenticationFilter;
|
||||||
import sonia.scm.web.security.AuthenticationManager;
|
|
||||||
import sonia.scm.web.security.ChainAuthenticatonManager;
|
|
||||||
import sonia.scm.web.security.DefaultAdministrationContext;
|
import sonia.scm.web.security.DefaultAdministrationContext;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
@@ -269,7 +263,6 @@ public class ScmServletModule extends JerseyServletModule
|
|||||||
// note CipherUtil uses an other generator
|
// note CipherUtil uses an other generator
|
||||||
bind(KeyGenerator.class).to(DefaultKeyGenerator.class);
|
bind(KeyGenerator.class).to(DefaultKeyGenerator.class);
|
||||||
bind(CipherHandler.class).toInstance(cu.getCipherHandler());
|
bind(CipherHandler.class).toInstance(cu.getCipherHandler());
|
||||||
bind(EncryptionHandler.class, MessageDigestEncryptionHandler.class);
|
|
||||||
bind(FileSystem.class, DefaultFileSystem.class);
|
bind(FileSystem.class, DefaultFileSystem.class);
|
||||||
|
|
||||||
// bind health check stuff
|
// bind health check stuff
|
||||||
@@ -280,10 +273,8 @@ public class ScmServletModule extends JerseyServletModule
|
|||||||
|
|
||||||
// bind security stuff
|
// bind security stuff
|
||||||
bind(PermissionResolver.class, RepositoryPermissionResolver.class);
|
bind(PermissionResolver.class, RepositoryPermissionResolver.class);
|
||||||
bind(AuthenticationManager.class, ChainAuthenticatonManager.class);
|
|
||||||
bind(SecuritySystem.class).to(DefaultSecuritySystem.class);
|
bind(SecuritySystem.class).to(DefaultSecuritySystem.class);
|
||||||
bind(AdministrationContext.class, DefaultAdministrationContext.class);
|
bind(AdministrationContext.class, DefaultAdministrationContext.class);
|
||||||
bind(LoginAttemptHandler.class, ConfigurableLoginAttemptHandler.class);
|
|
||||||
|
|
||||||
// bind cache
|
// bind cache
|
||||||
bind(CacheManager.class, GuavaCacheManager.class);
|
bind(CacheManager.class, GuavaCacheManager.class);
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ package sonia.scm.api.rest.resources;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authc.credential.PasswordService;
|
||||||
import org.apache.shiro.subject.Subject;
|
import org.apache.shiro.subject.Subject;
|
||||||
|
|
||||||
import org.codehaus.enunciate.jaxrs.TypeHint;
|
import org.codehaus.enunciate.jaxrs.TypeHint;
|
||||||
@@ -47,7 +48,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import sonia.scm.api.rest.RestActionResult;
|
import sonia.scm.api.rest.RestActionResult;
|
||||||
import sonia.scm.security.EncryptionHandler;
|
import sonia.scm.security.Role;
|
||||||
import sonia.scm.security.ScmSecurityException;
|
import sonia.scm.security.ScmSecurityException;
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.user.UserException;
|
import sonia.scm.user.UserException;
|
||||||
@@ -65,7 +66,6 @@ import javax.ws.rs.Produces;
|
|||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import sonia.scm.security.Role;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -88,14 +88,13 @@ public class ChangePasswordResource
|
|||||||
*
|
*
|
||||||
* @param userManager
|
* @param userManager
|
||||||
* @param encryptionHandler
|
* @param encryptionHandler
|
||||||
* @param securityContextProvider
|
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public ChangePasswordResource(UserManager userManager,
|
public ChangePasswordResource(UserManager userManager,
|
||||||
EncryptionHandler encryptionHandler)
|
PasswordService encryptionHandler)
|
||||||
{
|
{
|
||||||
this.userManager = userManager;
|
this.userManager = userManager;
|
||||||
this.encryptionHandler = encryptionHandler;
|
this.passwordService = encryptionHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
@@ -155,9 +154,9 @@ public class ChangePasswordResource
|
|||||||
{
|
{
|
||||||
User dbUser = userManager.get(currentUser.getName());
|
User dbUser = userManager.get(currentUser.getName());
|
||||||
|
|
||||||
if (encryptionHandler.encrypt(oldPassword).equals(dbUser.getPassword()))
|
if (passwordService.passwordsMatch(oldPassword, dbUser.getPassword()))
|
||||||
{
|
{
|
||||||
dbUser.setPassword(encryptionHandler.encrypt(newPassword));
|
dbUser.setPassword(passwordService.encryptPassword(newPassword));
|
||||||
userManager.modify(dbUser);
|
userManager.modify(dbUser);
|
||||||
response = Response.ok(new RestActionResult(true)).build();
|
response = Response.ok(new RestActionResult(true)).build();
|
||||||
}
|
}
|
||||||
@@ -183,8 +182,8 @@ public class ChangePasswordResource
|
|||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
private EncryptionHandler encryptionHandler;
|
private final PasswordService passwordService;
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
private UserManager userManager;
|
private final UserManager userManager;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,11 +39,11 @@ import com.google.inject.Inject;
|
|||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authc.credential.PasswordService;
|
||||||
|
|
||||||
import org.codehaus.enunciate.jaxrs.TypeHint;
|
import org.codehaus.enunciate.jaxrs.TypeHint;
|
||||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||||
|
|
||||||
import sonia.scm.security.EncryptionHandler;
|
|
||||||
import sonia.scm.security.Role;
|
import sonia.scm.security.Role;
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.user.UserException;
|
import sonia.scm.user.UserException;
|
||||||
@@ -95,15 +95,13 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param userManager
|
* @param userManager
|
||||||
* @param encryptionHandler
|
* @param passwordService
|
||||||
* @param securityContextProvider
|
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public UserResource(UserManager userManager,
|
public UserResource(UserManager userManager, PasswordService passwordService)
|
||||||
EncryptionHandler encryptionHandler)
|
|
||||||
{
|
{
|
||||||
super(userManager);
|
super(userManager);
|
||||||
this.encryptionHandler = encryptionHandler;
|
this.passwordService = passwordService;
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
@@ -386,12 +384,12 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
|||||||
|
|
||||||
if (Util.isNotEmpty(password))
|
if (Util.isNotEmpty(password))
|
||||||
{
|
{
|
||||||
user.setPassword(encryptionHandler.encrypt(password));
|
user.setPassword(passwordService.encryptPassword(password));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
private EncryptionHandler encryptionHandler;
|
private PasswordService passwordService;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,331 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer. 2. Redistributions in
|
|
||||||
* binary form must reproduce the above copyright notice, this list of
|
|
||||||
* conditions and the following disclaimer in the documentation and/or other
|
|
||||||
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
|
||||||
* nor the names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import com.google.inject.Singleton;
|
|
||||||
|
|
||||||
import org.apache.shiro.authc.AuthenticationException;
|
|
||||||
import org.apache.shiro.authc.AuthenticationToken;
|
|
||||||
import org.apache.shiro.authc.ExcessiveAttemptsException;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
|
||||||
import sonia.scm.web.security.AuthenticationResult;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class ConfigurableLoginAttemptHandler implements LoginAttemptHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the logger for ConfigurableLoginAttemptHandler
|
|
||||||
*/
|
|
||||||
private static final Logger logger =
|
|
||||||
LoggerFactory.getLogger(ConfigurableLoginAttemptHandler.class);
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param configuration
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
public ConfigurableLoginAttemptHandler(ScmConfiguration configuration)
|
|
||||||
{
|
|
||||||
this.configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param token
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void beforeAuthentication(AuthenticationToken token)
|
|
||||||
throws AuthenticationException
|
|
||||||
{
|
|
||||||
if (isEnabled())
|
|
||||||
{
|
|
||||||
handleBeforeAuthentication(token);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.trace("LoginAttemptHandler is disabled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param token
|
|
||||||
* @param result
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onSuccessfulAuthentication(AuthenticationToken token,
|
|
||||||
AuthenticationResult result)
|
|
||||||
throws AuthenticationException
|
|
||||||
{
|
|
||||||
if (isEnabled())
|
|
||||||
{
|
|
||||||
handleOnSuccessfulAuthentication(token);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.trace("LoginAttemptHandler is disabled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param token
|
|
||||||
* @param result
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onUnsuccessfulAuthentication(AuthenticationToken token,
|
|
||||||
AuthenticationResult result)
|
|
||||||
throws AuthenticationException
|
|
||||||
{
|
|
||||||
if (isEnabled())
|
|
||||||
{
|
|
||||||
handleOnUnsuccessfulAuthentication(token);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.trace("LoginAttemptHandler is disabled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param token
|
|
||||||
*/
|
|
||||||
private void handleBeforeAuthentication(AuthenticationToken token)
|
|
||||||
{
|
|
||||||
LoginAttempt attempt = getAttempt(token);
|
|
||||||
long time = System.currentTimeMillis() - attempt.lastAttempt;
|
|
||||||
|
|
||||||
if (time > getLoginAttemptLimitTimeout())
|
|
||||||
{
|
|
||||||
logger.debug("reset login attempts for {}, because of time",
|
|
||||||
token.getPrincipal());
|
|
||||||
attempt.reset();
|
|
||||||
}
|
|
||||||
else if (attempt.counter >= configuration.getLoginAttemptLimit())
|
|
||||||
{
|
|
||||||
logger.warn("account {} is temporary locked, because of {}",
|
|
||||||
token.getPrincipal(), attempt);
|
|
||||||
attempt.increase();
|
|
||||||
|
|
||||||
throw new ExcessiveAttemptsException("account is temporary locked");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param token
|
|
||||||
* @param result
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException
|
|
||||||
*/
|
|
||||||
private void handleOnSuccessfulAuthentication(AuthenticationToken token)
|
|
||||||
throws AuthenticationException
|
|
||||||
{
|
|
||||||
logger.debug("reset login attempts for {}, because of successful login",
|
|
||||||
token.getPrincipal());
|
|
||||||
getAttempt(token).reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param token
|
|
||||||
* @param result
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException
|
|
||||||
*/
|
|
||||||
private void handleOnUnsuccessfulAuthentication(AuthenticationToken token)
|
|
||||||
throws AuthenticationException
|
|
||||||
{
|
|
||||||
logger.debug("increase failed login attempts for {}", token.getPrincipal());
|
|
||||||
|
|
||||||
LoginAttempt attempt = getAttempt(token);
|
|
||||||
|
|
||||||
attempt.increase();
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param token
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private LoginAttempt getAttempt(AuthenticationToken token)
|
|
||||||
{
|
|
||||||
LoginAttempt freshAttempt = new LoginAttempt();
|
|
||||||
LoginAttempt attempt = attempts.putIfAbsent(token.getPrincipal(),
|
|
||||||
freshAttempt);
|
|
||||||
|
|
||||||
if (attempt == null)
|
|
||||||
{
|
|
||||||
attempt = freshAttempt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return attempt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private long getLoginAttemptLimitTimeout()
|
|
||||||
{
|
|
||||||
return TimeUnit.SECONDS.toMillis(
|
|
||||||
configuration.getLoginAttemptLimitTimeout());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean isEnabled()
|
|
||||||
{
|
|
||||||
return (configuration.getLoginAttemptLimit() > 0)
|
|
||||||
&& (configuration.getLoginAttemptLimitTimeout() > 0l);
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- inner classes --------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Login attempt
|
|
||||||
*/
|
|
||||||
private static class LoginAttempt
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
//J-
|
|
||||||
return Objects.toStringHelper(this)
|
|
||||||
.add("counter", counter)
|
|
||||||
.add("lastAttempt", lastAttempt)
|
|
||||||
.toString();
|
|
||||||
//J+
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
synchronized void increase()
|
|
||||||
{
|
|
||||||
counter++;
|
|
||||||
lastAttempt = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
synchronized void reset()
|
|
||||||
{
|
|
||||||
lastAttempt = -1l;
|
|
||||||
counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields -------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private int counter = 0;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private long lastAttempt = -1l;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final ConcurrentMap<Object, LoginAttempt> attempts =
|
|
||||||
new ConcurrentHashMap<Object, LoginAttempt>();
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final ScmConfiguration configuration;
|
|
||||||
}
|
|
||||||
228
scm-webapp/src/main/java/sonia/scm/security/DefaultRealm.java
Normal file
228
scm-webapp/src/main/java/sonia/scm/security/DefaultRealm.java
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||||
|
* binary form must reproduce the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer in the documentation and/or other
|
||||||
|
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||||
|
* nor the names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* http://bitbucket.org/sdorra/scm-manager
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
package sonia.scm.security;
|
||||||
|
|
||||||
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.ImmutableSet.Builder;
|
||||||
|
|
||||||
|
import org.apache.shiro.authc.AuthenticationException;
|
||||||
|
import org.apache.shiro.authc.AuthenticationInfo;
|
||||||
|
import org.apache.shiro.authc.AuthenticationToken;
|
||||||
|
import org.apache.shiro.authc.DisabledAccountException;
|
||||||
|
import org.apache.shiro.authc.SimpleAuthenticationInfo;
|
||||||
|
import org.apache.shiro.authc.UnknownAccountException;
|
||||||
|
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||||
|
import org.apache.shiro.authc.credential.PasswordMatcher;
|
||||||
|
import org.apache.shiro.authc.credential.PasswordService;
|
||||||
|
import org.apache.shiro.authz.AuthorizationInfo;
|
||||||
|
import org.apache.shiro.realm.AuthorizingRealm;
|
||||||
|
import org.apache.shiro.subject.PrincipalCollection;
|
||||||
|
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import sonia.scm.group.Group;
|
||||||
|
import sonia.scm.group.GroupDAO;
|
||||||
|
import sonia.scm.group.GroupNames;
|
||||||
|
import sonia.scm.user.User;
|
||||||
|
import sonia.scm.user.UserDAO;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.*;
|
||||||
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class DefaultRealm extends AuthorizingRealm
|
||||||
|
{
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String REALM = "DefaultRealm";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the logger for DefaultRealm
|
||||||
|
*/
|
||||||
|
private static final Logger logger =
|
||||||
|
LoggerFactory.getLogger(DefaultRealm.class);
|
||||||
|
|
||||||
|
//~--- constructors ---------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs ...
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param service
|
||||||
|
* @param collector
|
||||||
|
* @param userDAO
|
||||||
|
* @param groupDAO
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
public DefaultRealm(PasswordService service,
|
||||||
|
AuthorizationCollector collector, UserDAO userDAO, GroupDAO groupDAO)
|
||||||
|
{
|
||||||
|
this.collector = collector;
|
||||||
|
this.userDAO = userDAO;
|
||||||
|
this.groupDAO = groupDAO;
|
||||||
|
|
||||||
|
PasswordMatcher matcher = new PasswordMatcher();
|
||||||
|
|
||||||
|
matcher.setPasswordService(service);
|
||||||
|
setCredentialsMatcher(matcher);
|
||||||
|
setAuthenticationTokenClass(UsernamePasswordToken.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param token
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
* @throws AuthenticationException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected AuthenticationInfo doGetAuthenticationInfo(
|
||||||
|
AuthenticationToken token)
|
||||||
|
throws AuthenticationException
|
||||||
|
{
|
||||||
|
checkArgument(token instanceof UsernamePasswordToken, "%s is required",
|
||||||
|
UsernamePasswordToken.class);
|
||||||
|
|
||||||
|
UsernamePasswordToken upt = (UsernamePasswordToken) token;
|
||||||
|
String principal = upt.getUsername();
|
||||||
|
|
||||||
|
checkArgument(!Strings.isNullOrEmpty(principal), "username is required");
|
||||||
|
|
||||||
|
logger.debug("try to authenticate {}", principal);
|
||||||
|
|
||||||
|
User user = userDAO.get(principal);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
//J-
|
||||||
|
throw new UnknownAccountException(
|
||||||
|
String.format("unknown account %s", principal)
|
||||||
|
);
|
||||||
|
//J+
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.isActive())
|
||||||
|
{
|
||||||
|
//J-
|
||||||
|
throw new DisabledAccountException(
|
||||||
|
String.format("account %s is disabled", principal)
|
||||||
|
);
|
||||||
|
//J+
|
||||||
|
}
|
||||||
|
|
||||||
|
SimplePrincipalCollection collection = new SimplePrincipalCollection();
|
||||||
|
|
||||||
|
collection.add(principal, REALM);
|
||||||
|
collection.add(user, REALM);
|
||||||
|
collection.add(collectGroups(principal), REALM);
|
||||||
|
|
||||||
|
return new SimpleAuthenticationInfo(collection, user.getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param principals
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected AuthorizationInfo doGetAuthorizationInfo(
|
||||||
|
PrincipalCollection principals)
|
||||||
|
{
|
||||||
|
return collector.collect(principals);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param principal
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private GroupNames collectGroups(String principal)
|
||||||
|
{
|
||||||
|
Builder<String> builder = ImmutableSet.builder();
|
||||||
|
|
||||||
|
builder.add(GroupNames.AUTHENTICATED);
|
||||||
|
|
||||||
|
for (Group group : groupDAO.getAll())
|
||||||
|
{
|
||||||
|
if (group.isMember(principal))
|
||||||
|
{
|
||||||
|
builder.add(group.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupNames groups = new GroupNames(builder.build());
|
||||||
|
|
||||||
|
logger.debug("collected following groups for principal {}: {}", principal,
|
||||||
|
groups);
|
||||||
|
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private final AuthorizationCollector collector;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private final GroupDAO groupDAO;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private final UserDAO userDAO;
|
||||||
|
}
|
||||||
@@ -1,566 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import com.google.inject.Provider;
|
|
||||||
import com.google.inject.Singleton;
|
|
||||||
|
|
||||||
import org.apache.shiro.authc.AccountException;
|
|
||||||
import org.apache.shiro.authc.AuthenticationException;
|
|
||||||
import org.apache.shiro.authc.AuthenticationInfo;
|
|
||||||
import org.apache.shiro.authc.AuthenticationToken;
|
|
||||||
import org.apache.shiro.authc.DisabledAccountException;
|
|
||||||
import org.apache.shiro.authc.SimpleAuthenticationInfo;
|
|
||||||
import org.apache.shiro.authc.UnknownAccountException;
|
|
||||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
|
||||||
import org.apache.shiro.authc.pam.UnsupportedTokenException;
|
|
||||||
import org.apache.shiro.authz.AuthorizationInfo;
|
|
||||||
import org.apache.shiro.realm.AuthorizingRealm;
|
|
||||||
import org.apache.shiro.subject.PrincipalCollection;
|
|
||||||
import org.apache.shiro.subject.SimplePrincipalCollection;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import sonia.scm.HandlerEventType;
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
|
||||||
import sonia.scm.group.Group;
|
|
||||||
import sonia.scm.group.GroupManager;
|
|
||||||
import sonia.scm.group.GroupNames;
|
|
||||||
import sonia.scm.repository.RepositoryManager;
|
|
||||||
import sonia.scm.user.User;
|
|
||||||
import sonia.scm.user.UserDAO;
|
|
||||||
import sonia.scm.user.UserEventHack;
|
|
||||||
import sonia.scm.user.UserException;
|
|
||||||
import sonia.scm.user.UserManager;
|
|
||||||
import sonia.scm.util.Util;
|
|
||||||
import sonia.scm.web.security.AuthenticationManager;
|
|
||||||
import sonia.scm.web.security.AuthenticationResult;
|
|
||||||
import sonia.scm.web.security.AuthenticationState;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class ScmRealm extends AuthorizingRealm
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
public static final String NAME = "scm";
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private static final String SCM_CREDENTIALS = "SCM_CREDENTIALS";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the logger for ScmRealm
|
|
||||||
*/
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ScmRealm.class);
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
* @param configuration
|
|
||||||
* @param loginAttemptHandler
|
|
||||||
* @param collector
|
|
||||||
* @param userManager
|
|
||||||
* @param groupManager
|
|
||||||
* @param userDAO
|
|
||||||
* @param authenticator
|
|
||||||
* @param manager
|
|
||||||
* @param requestProvider
|
|
||||||
* @param responseProvider
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
public ScmRealm(ScmConfiguration configuration,
|
|
||||||
LoginAttemptHandler loginAttemptHandler, AuthorizationCollector collector,
|
|
||||||
UserManager userManager, GroupManager groupManager, UserDAO userDAO,
|
|
||||||
AuthenticationManager authenticator, RepositoryManager manager,
|
|
||||||
Provider<HttpServletRequest> requestProvider,
|
|
||||||
Provider<HttpServletResponse> responseProvider)
|
|
||||||
{
|
|
||||||
this.configuration = configuration;
|
|
||||||
this.loginAttemptHandler = loginAttemptHandler;
|
|
||||||
this.collector = collector;
|
|
||||||
this.userManager = userManager;
|
|
||||||
this.groupManager = groupManager;
|
|
||||||
this.userDAO = userDAO;
|
|
||||||
this.authenticator = authenticator;
|
|
||||||
this.requestProvider = requestProvider;
|
|
||||||
this.responseProvider = responseProvider;
|
|
||||||
|
|
||||||
// set token class
|
|
||||||
setAuthenticationTokenClass(UsernamePasswordToken.class);
|
|
||||||
|
|
||||||
// use own custom caching
|
|
||||||
setCachingEnabled(false);
|
|
||||||
setAuthenticationCachingEnabled(false);
|
|
||||||
setAuthorizationCachingEnabled(false);
|
|
||||||
|
|
||||||
// set components
|
|
||||||
setPermissionResolver(new RepositoryPermissionResolver());
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param authToken
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected AuthenticationInfo doGetAuthenticationInfo(
|
|
||||||
AuthenticationToken authToken)
|
|
||||||
throws AuthenticationException
|
|
||||||
{
|
|
||||||
if (!(authToken instanceof UsernamePasswordToken))
|
|
||||||
{
|
|
||||||
throw new UnsupportedTokenException("ScmAuthenticationToken is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
loginAttemptHandler.beforeAuthentication(authToken);
|
|
||||||
|
|
||||||
UsernamePasswordToken token = (UsernamePasswordToken) authToken;
|
|
||||||
|
|
||||||
AuthenticationInfo info = null;
|
|
||||||
AuthenticationResult result =
|
|
||||||
authenticator.authenticate(requestProvider.get(), responseProvider.get(),
|
|
||||||
token.getUsername(), new String(token.getPassword()));
|
|
||||||
|
|
||||||
if ((result != null) && (AuthenticationState.SUCCESS == result.getState()))
|
|
||||||
{
|
|
||||||
loginAttemptHandler.onSuccessfulAuthentication(authToken, result);
|
|
||||||
info = createAuthenticationInfo(token, result);
|
|
||||||
}
|
|
||||||
else if ((result != null)
|
|
||||||
&& (AuthenticationState.NOT_FOUND == result.getState()))
|
|
||||||
{
|
|
||||||
throw new UnknownAccountException(
|
|
||||||
"unknown account ".concat(token.getUsername()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
loginAttemptHandler.onUnsuccessfulAuthentication(authToken, result);
|
|
||||||
|
|
||||||
throw new AccountException("authentication failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param principals
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected AuthorizationInfo doGetAuthorizationInfo(
|
|
||||||
PrincipalCollection principals)
|
|
||||||
{
|
|
||||||
return collector.collect(principals);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param password
|
|
||||||
* @param ar
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Set<String> authenticate(HttpServletRequest request, String password,
|
|
||||||
AuthenticationResult ar)
|
|
||||||
{
|
|
||||||
Set<String> groupSet = null;
|
|
||||||
User user = ar.getUser();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
groupSet = createGroupSet(ar);
|
|
||||||
|
|
||||||
// check for admin user
|
|
||||||
checkForAuthenticatedAdmin(user, groupSet);
|
|
||||||
|
|
||||||
// store user
|
|
||||||
User dbUser = userDAO.get(user.getName());
|
|
||||||
|
|
||||||
if (dbUser != null)
|
|
||||||
{
|
|
||||||
checkDBForAdmin(user, dbUser);
|
|
||||||
checkDBForActive(user, dbUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create new user
|
|
||||||
else if (user.isValid())
|
|
||||||
{
|
|
||||||
user.setCreationDate(System.currentTimeMillis());
|
|
||||||
|
|
||||||
// TODO find a better way
|
|
||||||
UserEventHack.fireEvent(userManager, HandlerEventType.BEFORE_CREATE,
|
|
||||||
user);
|
|
||||||
userDAO.add(user);
|
|
||||||
UserEventHack.fireEvent(userManager, HandlerEventType.CREATE, user);
|
|
||||||
}
|
|
||||||
else if (logger.isErrorEnabled())
|
|
||||||
{
|
|
||||||
logger.error("could not create user {}, beacause it is not valid",
|
|
||||||
user.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.isActive())
|
|
||||||
{
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logGroups(user, groupSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
// store encrypted credentials in session
|
|
||||||
String credentials = user.getName();
|
|
||||||
|
|
||||||
if (Util.isNotEmpty(password))
|
|
||||||
{
|
|
||||||
credentials = credentials.concat(":").concat(password);
|
|
||||||
}
|
|
||||||
|
|
||||||
credentials = CipherUtil.getInstance().encode(credentials);
|
|
||||||
request.getSession(true).setAttribute(SCM_CREDENTIALS, credentials);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
String msg = "user ".concat(user.getName()).concat(" is deactivated");
|
|
||||||
|
|
||||||
if (logger.isWarnEnabled())
|
|
||||||
{
|
|
||||||
logger.warn(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new DisabledAccountException(msg);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
logger.error("authentication failed", ex);
|
|
||||||
|
|
||||||
throw new AuthenticationException("authentication failed", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return groupSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param dbUser
|
|
||||||
*/
|
|
||||||
private void checkDBForActive(User user, User dbUser)
|
|
||||||
{
|
|
||||||
|
|
||||||
// user is deactivated by database
|
|
||||||
if (!dbUser.isActive())
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("user {} is marked as deactivated by local database",
|
|
||||||
user.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
user.setActive(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param dbUser
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws UserException
|
|
||||||
*/
|
|
||||||
private void checkDBForAdmin(User user, User dbUser)
|
|
||||||
throws UserException, IOException
|
|
||||||
{
|
|
||||||
|
|
||||||
// if database user is an admin, set admin for the current user
|
|
||||||
if (dbUser.isAdmin())
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("user {} of type {} is marked as admin by local database",
|
|
||||||
user.getName(), user.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
user.setAdmin(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// modify existing user, copy properties except password and admin
|
|
||||||
if (user.copyProperties(dbUser, false))
|
|
||||||
{
|
|
||||||
user.setLastModified(System.currentTimeMillis());
|
|
||||||
UserEventHack.fireEvent(userManager, HandlerEventType.BEFORE_MODIFY, user);
|
|
||||||
userDAO.modify(user);
|
|
||||||
UserEventHack.fireEvent(userManager, HandlerEventType.MODIFY, user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param groupSet
|
|
||||||
*/
|
|
||||||
private void checkForAuthenticatedAdmin(User user, Set<String> groupSet)
|
|
||||||
{
|
|
||||||
if (!user.isAdmin())
|
|
||||||
{
|
|
||||||
user.setAdmin(isAdmin(user, groupSet));
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled() && user.isAdmin())
|
|
||||||
{
|
|
||||||
logger.debug("user {} is marked as admin by configuration",
|
|
||||||
user.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("authenticator {} marked user {} as admin", user.getType(),
|
|
||||||
user.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param token
|
|
||||||
* @param result
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private AuthenticationInfo createAuthenticationInfo(
|
|
||||||
UsernamePasswordToken token, AuthenticationResult result)
|
|
||||||
{
|
|
||||||
User user = result.getUser();
|
|
||||||
Collection<String> groups = authenticate(requestProvider.get(),
|
|
||||||
new String(token.getPassword()), result);
|
|
||||||
|
|
||||||
SimplePrincipalCollection collection = new SimplePrincipalCollection();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* the first (primary) principal should be a unique identifier
|
|
||||||
*/
|
|
||||||
collection.add(user.getId(), NAME);
|
|
||||||
collection.add(user, NAME);
|
|
||||||
collection.add(new GroupNames(groups), NAME);
|
|
||||||
|
|
||||||
return new SimpleAuthenticationInfo(collection, token.getPassword());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param ar
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Set<String> createGroupSet(AuthenticationResult ar)
|
|
||||||
{
|
|
||||||
Set<String> groupSet = Sets.newHashSet();
|
|
||||||
|
|
||||||
// add group for all authenticated users
|
|
||||||
groupSet.add(GroupNames.AUTHENTICATED);
|
|
||||||
|
|
||||||
// load external groups
|
|
||||||
Collection<String> extGroups = ar.getGroups();
|
|
||||||
|
|
||||||
if (extGroups != null)
|
|
||||||
{
|
|
||||||
groupSet.addAll(extGroups);
|
|
||||||
}
|
|
||||||
|
|
||||||
// load internal groups
|
|
||||||
loadGroups(ar.getUser(), groupSet);
|
|
||||||
|
|
||||||
return groupSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param groupSet
|
|
||||||
*/
|
|
||||||
private void loadGroups(User user, Set<String> groupSet)
|
|
||||||
{
|
|
||||||
Collection<Group> groupCollection =
|
|
||||||
groupManager.getGroupsForMember(user.getName());
|
|
||||||
|
|
||||||
if (groupCollection != null)
|
|
||||||
{
|
|
||||||
for (Group group : groupCollection)
|
|
||||||
{
|
|
||||||
groupSet.add(group.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param groups
|
|
||||||
*/
|
|
||||||
private void logGroups(User user, Set<String> groups)
|
|
||||||
{
|
|
||||||
StringBuilder msg = new StringBuilder("user ");
|
|
||||||
|
|
||||||
msg.append(user.getName());
|
|
||||||
|
|
||||||
if (Util.isNotEmpty(groups))
|
|
||||||
{
|
|
||||||
msg.append(" is member of ");
|
|
||||||
|
|
||||||
Joiner.on(", ").appendTo(msg, groups);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg.append(" is not a member of a group");
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug(msg.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param groups
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean isAdmin(User user, Collection<String> groups)
|
|
||||||
{
|
|
||||||
boolean result = false;
|
|
||||||
Set<String> adminUsers = configuration.getAdminUsers();
|
|
||||||
|
|
||||||
if (adminUsers != null)
|
|
||||||
{
|
|
||||||
result = adminUsers.contains(user.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
Set<String> adminGroups = configuration.getAdminGroups();
|
|
||||||
|
|
||||||
if (adminGroups != null)
|
|
||||||
{
|
|
||||||
result = Util.containsOne(adminGroups, groups);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final AuthenticationManager authenticator;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final AuthorizationCollector collector;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final ScmConfiguration configuration;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final GroupManager groupManager;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final LoginAttemptHandler loginAttemptHandler;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final Provider<HttpServletRequest> requestProvider;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final Provider<HttpServletResponse> responseProvider;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final UserDAO userDAO;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final UserManager userManager;
|
|
||||||
}
|
|
||||||
@@ -1,398 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.web.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import com.google.inject.Singleton;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import sonia.scm.SCMContextProvider;
|
|
||||||
import sonia.scm.cache.Cache;
|
|
||||||
import sonia.scm.cache.CacheManager;
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
|
||||||
import sonia.scm.security.EncryptionHandler;
|
|
||||||
import sonia.scm.user.User;
|
|
||||||
import sonia.scm.user.UserManager;
|
|
||||||
import sonia.scm.util.AssertUtil;
|
|
||||||
import sonia.scm.util.IOUtil;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class ChainAuthenticatonManager extends AbstractAuthenticationManager
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
public static final String CACHE_NAME = "sonia.cache.auth";
|
|
||||||
|
|
||||||
/** the logger for ChainAuthenticatonManager */
|
|
||||||
private static final Logger logger =
|
|
||||||
LoggerFactory.getLogger(ChainAuthenticatonManager.class);
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param configuration
|
|
||||||
* @param userManager
|
|
||||||
* @param authenticationHandlerSet
|
|
||||||
* @param encryptionHandler
|
|
||||||
* @param cacheManager
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
public ChainAuthenticatonManager(ScmConfiguration configuration,
|
|
||||||
UserManager userManager,
|
|
||||||
Set<AuthenticationHandler> authenticationHandlerSet,
|
|
||||||
EncryptionHandler encryptionHandler, CacheManager cacheManager)
|
|
||||||
{
|
|
||||||
AssertUtil.assertIsNotEmpty(authenticationHandlerSet);
|
|
||||||
AssertUtil.assertIsNotNull(cacheManager);
|
|
||||||
this.configuration = configuration;
|
|
||||||
this.authenticationHandlers = sort(userManager, authenticationHandlerSet);
|
|
||||||
this.encryptionHandler = encryptionHandler;
|
|
||||||
this.cache = cacheManager.getCache(CACHE_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @param username
|
|
||||||
* @param password
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public AuthenticationResult authenticate(HttpServletRequest request,
|
|
||||||
HttpServletResponse response, String username, String password)
|
|
||||||
{
|
|
||||||
AssertUtil.assertIsNotEmpty(username);
|
|
||||||
AssertUtil.assertIsNotEmpty(password);
|
|
||||||
|
|
||||||
String encryptedPassword = encryptionHandler.encrypt(password);
|
|
||||||
AuthenticationResult ar = getCached(username, encryptedPassword);
|
|
||||||
|
|
||||||
if (ar == null)
|
|
||||||
{
|
|
||||||
if (logger.isTraceEnabled())
|
|
||||||
{
|
|
||||||
logger.trace("no authentication result for user {} found in cache",
|
|
||||||
username);
|
|
||||||
}
|
|
||||||
|
|
||||||
ar = doAuthentication(request, response, username, password);
|
|
||||||
|
|
||||||
if ((ar != null) && ar.isCacheable())
|
|
||||||
{
|
|
||||||
cache.put(username,
|
|
||||||
new AuthenticationCacheValue(ar, encryptedPassword));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("authenticate {} via cache", username);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ar;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException
|
|
||||||
{
|
|
||||||
for (AuthenticationHandler authenticator : authenticationHandlers)
|
|
||||||
{
|
|
||||||
if (logger.isTraceEnabled())
|
|
||||||
{
|
|
||||||
logger.trace("close authenticator {}", authenticator.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
IOUtil.close(authenticator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void init(SCMContextProvider context)
|
|
||||||
{
|
|
||||||
for (AuthenticationHandler authenticator : authenticationHandlers)
|
|
||||||
{
|
|
||||||
if (logger.isTraceEnabled())
|
|
||||||
{
|
|
||||||
logger.trace("initialize authenticator {}", authenticator.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticator.init(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param result
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
boolean stopChain(AuthenticationResult result)
|
|
||||||
{
|
|
||||||
return (result != null) && (result.getState() != null)
|
|
||||||
&& (result.getState().isSuccessfully()
|
|
||||||
|| ((result.getState() == AuthenticationState.FAILED)
|
|
||||||
&&!configuration.isSkipFailedAuthenticators()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @param username
|
|
||||||
* @param password
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private AuthenticationResult doAuthentication(HttpServletRequest request,
|
|
||||||
HttpServletResponse response, String username, String password)
|
|
||||||
{
|
|
||||||
AuthenticationResult ar = null;
|
|
||||||
|
|
||||||
if (logger.isTraceEnabled())
|
|
||||||
{
|
|
||||||
logger.trace("start authentication chain for user {}", username);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (AuthenticationHandler authenticator : authenticationHandlers)
|
|
||||||
{
|
|
||||||
if (logger.isTraceEnabled())
|
|
||||||
{
|
|
||||||
logger.trace("check authenticator {} for user {}",
|
|
||||||
authenticator.getClass(), username);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AuthenticationResult result = authenticator.authenticate(request,
|
|
||||||
response, username, password);
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("authenticator {} ends with result, {}",
|
|
||||||
authenticator.getClass().getName(), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stopChain(result))
|
|
||||||
{
|
|
||||||
if (result.getState().isSuccessfully() && (result.getUser() != null))
|
|
||||||
{
|
|
||||||
User user = result.getUser();
|
|
||||||
|
|
||||||
user.setType(authenticator.getType());
|
|
||||||
ar = result;
|
|
||||||
|
|
||||||
// notify authentication listeners
|
|
||||||
fireAuthenticationEvent(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
logger.error(
|
|
||||||
"error durring authentication process of ".concat(
|
|
||||||
authenticator.getClass().getName()), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ar;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param userManager
|
|
||||||
* @param authenticationHandlerSet
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
private List<AuthenticationHandler> sort(UserManager userManager,
|
|
||||||
Set<AuthenticationHandler> authenticationHandlerSet)
|
|
||||||
{
|
|
||||||
List<AuthenticationHandler> handlers =
|
|
||||||
Lists.newArrayListWithCapacity(authenticationHandlerSet.size());
|
|
||||||
|
|
||||||
String first = Strings.nullToEmpty(userManager.getDefaultType());
|
|
||||||
|
|
||||||
for (AuthenticationHandler handler : authenticationHandlerSet)
|
|
||||||
{
|
|
||||||
if (first.equals(handler.getType()))
|
|
||||||
{
|
|
||||||
handlers.add(0, handler);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
handlers.add(handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param username
|
|
||||||
* @param encryptedPassword
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private AuthenticationResult getCached(String username,
|
|
||||||
String encryptedPassword)
|
|
||||||
{
|
|
||||||
AuthenticationResult result = null;
|
|
||||||
AuthenticationCacheValue value = cache.get(username);
|
|
||||||
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
String cachedPassword = value.password;
|
|
||||||
|
|
||||||
if (cachedPassword.equals(encryptedPassword))
|
|
||||||
{
|
|
||||||
result = value.authenticationResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- inner classes --------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @version Enter version here..., 2011-01-15
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
private static class AuthenticationCacheValue implements Serializable
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private static final long serialVersionUID = 2201116145941277549L;
|
|
||||||
|
|
||||||
//~--- constructors -------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param ar
|
|
||||||
* @param password
|
|
||||||
*/
|
|
||||||
public AuthenticationCacheValue(AuthenticationResult ar, String password)
|
|
||||||
{
|
|
||||||
this.authenticationResult =
|
|
||||||
new AuthenticationResult(ar.getUser().clone(), ar.getGroups(),
|
|
||||||
ar.getState());
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields -------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private AuthenticationResult authenticationResult;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String password;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** authentication handlers */
|
|
||||||
private final List<AuthenticationHandler> authenticationHandlers;
|
|
||||||
|
|
||||||
/** authentication cache */
|
|
||||||
private final Cache<String, AuthenticationCacheValue> cache;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final ScmConfiguration configuration;
|
|
||||||
|
|
||||||
/** encryption handler */
|
|
||||||
private final EncryptionHandler encryptionHandler;
|
|
||||||
}
|
|
||||||
@@ -53,7 +53,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
import sonia.scm.SCMContext;
|
import sonia.scm.SCMContext;
|
||||||
import sonia.scm.group.GroupNames;
|
import sonia.scm.group.GroupNames;
|
||||||
import sonia.scm.security.Role;
|
import sonia.scm.security.Role;
|
||||||
import sonia.scm.security.ScmRealm;
|
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.util.AssertUtil;
|
import sonia.scm.util.AssertUtil;
|
||||||
|
|
||||||
@@ -75,6 +74,9 @@ public class DefaultAdministrationContext implements AdministrationContext
|
|||||||
public static final String SYSTEM_ACCOUNT =
|
public static final String SYSTEM_ACCOUNT =
|
||||||
"/sonia/scm/web/security/system-account.xml";
|
"/sonia/scm/web/security/system-account.xml";
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private static final String REALM = "AdminRealm";
|
||||||
|
|
||||||
/** the logger for DefaultAdministrationContext */
|
/** the logger for DefaultAdministrationContext */
|
||||||
private static final Logger logger =
|
private static final Logger logger =
|
||||||
LoggerFactory.getLogger(DefaultAdministrationContext.class);
|
LoggerFactory.getLogger(DefaultAdministrationContext.class);
|
||||||
@@ -169,9 +171,9 @@ public class DefaultAdministrationContext implements AdministrationContext
|
|||||||
{
|
{
|
||||||
SimplePrincipalCollection collection = new SimplePrincipalCollection();
|
SimplePrincipalCollection collection = new SimplePrincipalCollection();
|
||||||
|
|
||||||
collection.add(adminUser.getId(), ScmRealm.NAME);
|
collection.add(adminUser.getId(), REALM);
|
||||||
collection.add(adminUser, ScmRealm.NAME);
|
collection.add(adminUser, REALM);
|
||||||
collection.add(new GroupNames(), ScmRealm.NAME);
|
collection.add(new GroupNames(), REALM);
|
||||||
|
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,230 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.web.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import com.google.inject.Singleton;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import sonia.scm.SCMContextProvider;
|
|
||||||
import sonia.scm.security.EncryptionHandler;
|
|
||||||
import sonia.scm.user.User;
|
|
||||||
import sonia.scm.user.UserManager;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import sonia.scm.plugin.Extension;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
@Extension
|
|
||||||
@Singleton
|
|
||||||
public class DefaultAuthenticationHandler implements AuthenticationHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
public static final String NAME_DIRECTORY = "users";
|
|
||||||
|
|
||||||
/** the logger for XmlAuthenticationHandler */
|
|
||||||
private static final Logger logger =
|
|
||||||
LoggerFactory.getLogger(DefaultAuthenticationHandler.class);
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param userManager
|
|
||||||
* @param encryptionHandler
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
public DefaultAuthenticationHandler(UserManager userManager,
|
|
||||||
EncryptionHandler encryptionHandler)
|
|
||||||
{
|
|
||||||
this.userManager = userManager;
|
|
||||||
this.encryptionHandler = encryptionHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @param username
|
|
||||||
* @param password
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public AuthenticationResult authenticate(HttpServletRequest request,
|
|
||||||
HttpServletResponse response, String username, String password)
|
|
||||||
{
|
|
||||||
AuthenticationResult result = null;
|
|
||||||
User user = userManager.get(username);
|
|
||||||
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
if (userManager.getDefaultType().equals(user.getType()))
|
|
||||||
{
|
|
||||||
result = authenticate(user, username, password);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("{} is not an {} user", username,
|
|
||||||
userManager.getDefaultType());
|
|
||||||
}
|
|
||||||
|
|
||||||
result = AuthenticationResult.NOT_FOUND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("could not find user {}", username);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = AuthenticationResult.NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException
|
|
||||||
{
|
|
||||||
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param provider
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void init(SCMContextProvider provider)
|
|
||||||
{
|
|
||||||
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getType()
|
|
||||||
{
|
|
||||||
return userManager.getDefaultType();
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param username
|
|
||||||
* @param password
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private AuthenticationResult authenticate(User user, String username,
|
|
||||||
String password)
|
|
||||||
{
|
|
||||||
AuthenticationResult result = null;
|
|
||||||
String encryptedPassword = encryptionHandler.encrypt(password);
|
|
||||||
|
|
||||||
if (!encryptedPassword.equalsIgnoreCase(user.getPassword()))
|
|
||||||
{
|
|
||||||
user = null;
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("password for user {} is wrong", username);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = AuthenticationResult.FAILED;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("user {} successfully prepared for login", username);
|
|
||||||
}
|
|
||||||
|
|
||||||
user.setPassword(null);
|
|
||||||
result = new AuthenticationResult(user, AuthenticationState.SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private EncryptionHandler encryptionHandler;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private UserManager userManager;
|
|
||||||
}
|
|
||||||
@@ -50,6 +50,7 @@ import static sonia.scm.it.IntegrationTestUtil.*;
|
|||||||
import com.sun.jersey.api.client.Client;
|
import com.sun.jersey.api.client.Client;
|
||||||
import com.sun.jersey.api.client.ClientResponse;
|
import com.sun.jersey.api.client.ClientResponse;
|
||||||
import com.sun.jersey.api.client.WebResource;
|
import com.sun.jersey.api.client.WebResource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
@@ -126,9 +127,8 @@ public class DeactivatedUserITCase
|
|||||||
Client client = createClient();
|
Client client = createClient();
|
||||||
ClientResponse response = authenticate(client, slarti.getName(),
|
ClientResponse response = authenticate(client, slarti.getName(),
|
||||||
"slart123");
|
"slart123");
|
||||||
|
|
||||||
assertNotNull(response);
|
assertNotNull(response);
|
||||||
assertEquals(401, response.getStatus());
|
assertEquals(HttpServletResponse.SC_FORBIDDEN, response.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,139 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer. 2. Redistributions in
|
|
||||||
* binary form must reproduce the above copyright notice, this list of
|
|
||||||
* conditions and the following disclaimer in the documentation and/or other
|
|
||||||
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
|
||||||
* nor the names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import org.apache.shiro.authc.ExcessiveAttemptsException;
|
|
||||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
|
||||||
import sonia.scm.web.security.AuthenticationResult;
|
|
||||||
import sonia.scm.web.security.AuthenticationState;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public class ConfigurableLoginAttemptHandlerTest
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test(expected = ExcessiveAttemptsException.class)
|
|
||||||
public void testLoginAttemptLimitReached()
|
|
||||||
{
|
|
||||||
LoginAttemptHandler handler = createHandler(2, 2);
|
|
||||||
UsernamePasswordToken token = new UsernamePasswordToken("hansolo", "hobbo");
|
|
||||||
|
|
||||||
handler.beforeAuthentication(token);
|
|
||||||
handler.onUnsuccessfulAuthentication(token, AuthenticationResult.FAILED);
|
|
||||||
handler.beforeAuthentication(token);
|
|
||||||
handler.onUnsuccessfulAuthentication(token, AuthenticationResult.FAILED);
|
|
||||||
handler.beforeAuthentication(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @throws InterruptedException
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testLoginAttemptLimitTimeout() throws InterruptedException
|
|
||||||
{
|
|
||||||
LoginAttemptHandler handler = createHandler(2, 1);
|
|
||||||
UsernamePasswordToken token = new UsernamePasswordToken("hansolo", "hobbo");
|
|
||||||
|
|
||||||
handler.beforeAuthentication(token);
|
|
||||||
handler.onUnsuccessfulAuthentication(token, AuthenticationResult.FAILED);
|
|
||||||
handler.beforeAuthentication(token);
|
|
||||||
handler.onUnsuccessfulAuthentication(token, AuthenticationResult.FAILED);
|
|
||||||
Thread.currentThread().sleep(TimeUnit.MILLISECONDS.toMillis(1200l));
|
|
||||||
handler.beforeAuthentication(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @throws InterruptedException
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testLoginAttemptResetOnSuccess() throws InterruptedException
|
|
||||||
{
|
|
||||||
LoginAttemptHandler handler = createHandler(2, 1);
|
|
||||||
UsernamePasswordToken token = new UsernamePasswordToken("hansolo", "hobbo");
|
|
||||||
|
|
||||||
handler.beforeAuthentication(token);
|
|
||||||
handler.onUnsuccessfulAuthentication(token, AuthenticationResult.FAILED);
|
|
||||||
handler.beforeAuthentication(token);
|
|
||||||
handler.onUnsuccessfulAuthentication(token, AuthenticationResult.FAILED);
|
|
||||||
|
|
||||||
handler.onSuccessfulAuthentication(token,
|
|
||||||
new AuthenticationResult(AuthenticationState.SUCCESS));
|
|
||||||
|
|
||||||
handler.beforeAuthentication(token);
|
|
||||||
handler.onUnsuccessfulAuthentication(token, AuthenticationResult.FAILED);
|
|
||||||
handler.beforeAuthentication(token);
|
|
||||||
handler.onUnsuccessfulAuthentication(token, AuthenticationResult.FAILED);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param loginAttemptLimit
|
|
||||||
* @param loginAttemptLimitTimeout
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private LoginAttemptHandler createHandler(int loginAttemptLimit,
|
|
||||||
long loginAttemptLimitTimeout)
|
|
||||||
{
|
|
||||||
ScmConfiguration configuration = new ScmConfiguration();
|
|
||||||
|
|
||||||
configuration.setLoginAttemptLimit(loginAttemptLimit);
|
|
||||||
configuration.setLoginAttemptLimitTimeout(loginAttemptLimitTimeout);
|
|
||||||
|
|
||||||
return new ConfigurableLoginAttemptHandler(configuration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,308 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2014, Sebastian Sdorra
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* http://bitbucket.org/sdorra/scm-manager
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
package sonia.scm.security;
|
||||||
|
|
||||||
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import org.apache.shiro.authc.AuthenticationInfo;
|
||||||
|
import org.apache.shiro.authc.AuthenticationToken;
|
||||||
|
import org.apache.shiro.authc.DisabledAccountException;
|
||||||
|
import org.apache.shiro.authc.IncorrectCredentialsException;
|
||||||
|
import org.apache.shiro.authc.UnknownAccountException;
|
||||||
|
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||||
|
import org.apache.shiro.authc.credential.DefaultPasswordService;
|
||||||
|
import org.apache.shiro.crypto.hash.DefaultHashService;
|
||||||
|
import org.apache.shiro.subject.PrincipalCollection;
|
||||||
|
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import sonia.scm.group.Group;
|
||||||
|
import sonia.scm.group.GroupDAO;
|
||||||
|
import sonia.scm.group.GroupNames;
|
||||||
|
import sonia.scm.user.User;
|
||||||
|
import sonia.scm.user.UserDAO;
|
||||||
|
import sonia.scm.user.UserTestData;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
*/
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class DefaultRealmTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test(expected = DisabledAccountException.class)
|
||||||
|
public void testDisabledAccount()
|
||||||
|
{
|
||||||
|
User user = UserTestData.createMarvin();
|
||||||
|
|
||||||
|
user.setActive(false);
|
||||||
|
|
||||||
|
UsernamePasswordToken token = daoUser(user, "secret");
|
||||||
|
|
||||||
|
realm.getAuthenticationInfo(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetAuthorizationInfo()
|
||||||
|
{
|
||||||
|
SimplePrincipalCollection col = new SimplePrincipalCollection();
|
||||||
|
|
||||||
|
realm.doGetAuthorizationInfo(col);
|
||||||
|
verify(collector, times(1)).collect(col);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGroupCollection()
|
||||||
|
{
|
||||||
|
User user = UserTestData.createTrillian();
|
||||||
|
//J-
|
||||||
|
List<Group> groups = Lists.newArrayList(
|
||||||
|
new Group(DefaultRealm.REALM, "scm", user.getName()),
|
||||||
|
new Group(DefaultRealm.REALM, "developers", "perfect")
|
||||||
|
);
|
||||||
|
//J+
|
||||||
|
|
||||||
|
when(groupDAO.getAll()).thenReturn(groups);
|
||||||
|
|
||||||
|
UsernamePasswordToken token = daoUser(user, "secret");
|
||||||
|
AuthenticationInfo info = realm.getAuthenticationInfo(token);
|
||||||
|
GroupNames groupNames = info.getPrincipals().oneByType(GroupNames.class);
|
||||||
|
|
||||||
|
assertNotNull(groupNames);
|
||||||
|
assertThat(groupNames.getCollection(), hasSize(2));
|
||||||
|
assertThat(groupNames, hasItems("scm", GroupNames.AUTHENTICATED));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSimpleAuthentication()
|
||||||
|
{
|
||||||
|
User user = UserTestData.createTrillian();
|
||||||
|
UsernamePasswordToken token = daoUser(user, "secret");
|
||||||
|
AuthenticationInfo info = realm.getAuthenticationInfo(token);
|
||||||
|
|
||||||
|
assertNotNull(info);
|
||||||
|
|
||||||
|
PrincipalCollection collection = info.getPrincipals();
|
||||||
|
|
||||||
|
assertEquals(token.getUsername(), collection.getPrimaryPrincipal());
|
||||||
|
assertThat(collection.getRealmNames(), hasSize(1));
|
||||||
|
assertThat(collection.getRealmNames(), hasItem(DefaultRealm.REALM));
|
||||||
|
assertEquals(user, collection.oneByType(User.class));
|
||||||
|
|
||||||
|
GroupNames groups = collection.oneByType(GroupNames.class);
|
||||||
|
|
||||||
|
assertNotNull(groups);
|
||||||
|
assertThat(groups.getCollection(), hasSize(1));
|
||||||
|
assertThat(groups.getCollection(), hasItem(GroupNames.AUTHENTICATED));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test(expected = UnknownAccountException.class)
|
||||||
|
public void testUnknownAccount()
|
||||||
|
{
|
||||||
|
realm.getAuthenticationInfo(new UsernamePasswordToken("tricia", "secret"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testWithoutUsername()
|
||||||
|
{
|
||||||
|
realm.getAuthenticationInfo(new UsernamePasswordToken(null, "secret"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test(expected = IncorrectCredentialsException.class)
|
||||||
|
public void testWrongCredentials()
|
||||||
|
{
|
||||||
|
UsernamePasswordToken token = daoUser(UserTestData.createDent(), "secret");
|
||||||
|
|
||||||
|
token.setPassword("secret123".toCharArray());
|
||||||
|
realm.getAuthenticationInfo(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testWrongToken()
|
||||||
|
{
|
||||||
|
realm.getAuthenticationInfo(new OtherAuthenticationToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- set methods ----------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Before
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
service = new DefaultPasswordService();
|
||||||
|
|
||||||
|
DefaultHashService hashService = new DefaultHashService();
|
||||||
|
|
||||||
|
// use a small number of iterations for faster test execution
|
||||||
|
hashService.setHashIterations(512);
|
||||||
|
service.setHashService(hashService);
|
||||||
|
realm = new DefaultRealm(service, collector, userDAO, groupDAO);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* @param password
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private UsernamePasswordToken daoUser(User user, String password)
|
||||||
|
{
|
||||||
|
user.setPassword(service.encryptPassword(password));
|
||||||
|
when(userDAO.get(user.getName())).thenReturn(user);
|
||||||
|
|
||||||
|
return new UsernamePasswordToken(user.getName(), password);
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- inner classes --------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @version Enter version here..., 14/12/13
|
||||||
|
* @author Enter your name here...
|
||||||
|
*/
|
||||||
|
private static class OtherAuthenticationToken implements AuthenticationToken
|
||||||
|
{
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private static final long serialVersionUID = 8891352342377018022L;
|
||||||
|
|
||||||
|
//~--- get methods --------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object getCredentials()
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); // To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object getPrincipal()
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); // To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
@Mock
|
||||||
|
private AuthorizationCollector collector;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
@Mock
|
||||||
|
private GroupDAO groupDAO;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private DefaultRealm realm;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private DefaultPasswordService service;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
@Mock
|
||||||
|
private UserDAO userDAO;
|
||||||
|
}
|
||||||
@@ -1,627 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.inject.Provider;
|
|
||||||
|
|
||||||
import org.apache.shiro.authc.AccountException;
|
|
||||||
import org.apache.shiro.authc.AuthenticationException;
|
|
||||||
import org.apache.shiro.authc.AuthenticationInfo;
|
|
||||||
import org.apache.shiro.authc.AuthenticationToken;
|
|
||||||
import org.apache.shiro.authc.UnknownAccountException;
|
|
||||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
|
||||||
import org.apache.shiro.authz.AuthorizationInfo;
|
|
||||||
import org.apache.shiro.authz.Permission;
|
|
||||||
import org.apache.shiro.subject.PrincipalCollection;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
|
|
||||||
import sonia.scm.cache.CacheManager;
|
|
||||||
import sonia.scm.cache.MapCacheManager;
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
|
||||||
import sonia.scm.group.Group;
|
|
||||||
import sonia.scm.group.GroupManager;
|
|
||||||
import sonia.scm.group.GroupNames;
|
|
||||||
import sonia.scm.repository.PermissionType;
|
|
||||||
import sonia.scm.repository.Repository;
|
|
||||||
import sonia.scm.repository.RepositoryDAO;
|
|
||||||
import sonia.scm.repository.RepositoryTestData;
|
|
||||||
import sonia.scm.user.User;
|
|
||||||
import sonia.scm.user.UserDAO;
|
|
||||||
import sonia.scm.user.UserManager;
|
|
||||||
import sonia.scm.user.UserTestData;
|
|
||||||
import sonia.scm.web.security.AuthenticationManager;
|
|
||||||
import sonia.scm.web.security.AuthenticationResult;
|
|
||||||
import sonia.scm.web.security.AuthenticationState;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import javax.servlet.http.HttpSession;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public class ScmRealmTest
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test(expected = UnknownAccountException.class)
|
|
||||||
public void testAuthenticationWithUknownUser()
|
|
||||||
{
|
|
||||||
User trillian = createSampleUser();
|
|
||||||
ScmRealm realm = createRealm(trillian);
|
|
||||||
|
|
||||||
realm.getAuthenticationInfo(token("marvin", trillian.getPassword()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthorizationAdminPermissions()
|
|
||||||
{
|
|
||||||
User trillian = createSampleUser();
|
|
||||||
|
|
||||||
trillian.setAdmin(true);
|
|
||||||
|
|
||||||
AuthorizationInfo ai = authorizationInfo(trillian);
|
|
||||||
Collection<Permission> permissions = ai.getObjectPermissions();
|
|
||||||
|
|
||||||
assertNotNull(permissions);
|
|
||||||
assertFalse(permissions.isEmpty());
|
|
||||||
assertEquals(1, permissions.size());
|
|
||||||
//J-
|
|
||||||
assertTrue(
|
|
||||||
permissions.contains(new RepositoryPermission("*", PermissionType.OWNER))
|
|
||||||
);
|
|
||||||
//J+
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthorizationAdminRoles()
|
|
||||||
{
|
|
||||||
User trillian = createSampleUser();
|
|
||||||
|
|
||||||
trillian.setAdmin(true);
|
|
||||||
|
|
||||||
AuthorizationInfo aci = authorizationInfo(trillian);
|
|
||||||
Collection<String> roles = aci.getRoles();
|
|
||||||
|
|
||||||
assertNotNull(roles);
|
|
||||||
assertEquals(2, roles.size());
|
|
||||||
assertTrue(roles.contains(Role.ADMIN));
|
|
||||||
assertTrue(roles.contains(Role.USER));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthorizationDefaultUserPermissions()
|
|
||||||
{
|
|
||||||
User trillian = createSampleUser();
|
|
||||||
|
|
||||||
AuthorizationInfo ai = authorizationInfo(trillian);
|
|
||||||
Collection<Permission> permissions = ai.getObjectPermissions();
|
|
||||||
|
|
||||||
assertNotNull(permissions);
|
|
||||||
assertTrue(permissions.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthorizationGroupPermissions()
|
|
||||||
{
|
|
||||||
User trillian = createSampleUser();
|
|
||||||
|
|
||||||
String g1 = "g1";
|
|
||||||
String g2 = "g2";
|
|
||||||
Group g3 = new Group("xml", "g3");
|
|
||||||
Group g4 = new Group("xml", "g4");
|
|
||||||
|
|
||||||
Repository r1 = RepositoryTestData.create42Puzzle();
|
|
||||||
|
|
||||||
prepareRepo(r1, g1, PermissionType.READ, true);
|
|
||||||
|
|
||||||
Repository r2 = RepositoryTestData.createHappyVerticalPeopleTransporter();
|
|
||||||
|
|
||||||
prepareRepo(r2, g2, PermissionType.WRITE, true);
|
|
||||||
|
|
||||||
Repository r3 = RepositoryTestData.createHeartOfGold();
|
|
||||||
|
|
||||||
prepareRepo(r3, g3, PermissionType.OWNER);
|
|
||||||
|
|
||||||
Repository r4 = RepositoryTestData.createRestaurantAtTheEndOfTheUniverse();
|
|
||||||
|
|
||||||
Set<Repository> repositories = ImmutableSet.of(r1, r2, r3, r4);
|
|
||||||
ScmRealm realm = createRealm(trillian, ImmutableSet.of(g1, g2),
|
|
||||||
ImmutableSet.of(g3, g4), repositories);
|
|
||||||
AuthenticationInfo aui = realm.getAuthenticationInfo(token(trillian));
|
|
||||||
AuthorizationInfo aci = realm.doGetAuthorizationInfo(aui.getPrincipals());
|
|
||||||
|
|
||||||
Collection<Permission> permissions = aci.getObjectPermissions();
|
|
||||||
|
|
||||||
assertNotNull(permissions);
|
|
||||||
assertFalse(permissions.isEmpty());
|
|
||||||
assertEquals(3, permissions.size());
|
|
||||||
containPermission(permissions, r1, PermissionType.READ);
|
|
||||||
containPermission(permissions, r2, PermissionType.WRITE);
|
|
||||||
containPermission(permissions, r3, PermissionType.OWNER);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthorizationUserPermissions()
|
|
||||||
{
|
|
||||||
User trillian = createSampleUser();
|
|
||||||
Repository r1 = RepositoryTestData.create42Puzzle();
|
|
||||||
|
|
||||||
prepareRepo(r1, trillian, PermissionType.READ);
|
|
||||||
|
|
||||||
Repository r2 = RepositoryTestData.createHappyVerticalPeopleTransporter();
|
|
||||||
|
|
||||||
prepareRepo(r2, trillian, PermissionType.WRITE);
|
|
||||||
|
|
||||||
Repository r3 = RepositoryTestData.createHeartOfGold();
|
|
||||||
|
|
||||||
prepareRepo(r3, trillian, PermissionType.OWNER);
|
|
||||||
|
|
||||||
Repository r4 = RepositoryTestData.createRestaurantAtTheEndOfTheUniverse();
|
|
||||||
|
|
||||||
Set<Repository> repositories = ImmutableSet.of(r1, r2, r3, r4);
|
|
||||||
|
|
||||||
ScmRealm realm = createRealm(trillian, null, null, repositories);
|
|
||||||
AuthenticationInfo aui = realm.getAuthenticationInfo(token(trillian));
|
|
||||||
AuthorizationInfo aci = realm.doGetAuthorizationInfo(aui.getPrincipals());
|
|
||||||
Collection<Permission> permissions = aci.getObjectPermissions();
|
|
||||||
|
|
||||||
assertNotNull(permissions);
|
|
||||||
assertFalse(permissions.isEmpty());
|
|
||||||
assertEquals(3, permissions.size());
|
|
||||||
containPermission(permissions, r1, PermissionType.READ);
|
|
||||||
containPermission(permissions, r2, PermissionType.WRITE);
|
|
||||||
containPermission(permissions, r3, PermissionType.OWNER);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthorizationUserRoles()
|
|
||||||
{
|
|
||||||
AuthorizationInfo aci = authorizationInfo(createSampleUser());
|
|
||||||
Collection<String> roles = aci.getRoles();
|
|
||||||
|
|
||||||
assertNotNull(roles);
|
|
||||||
assertEquals(1, roles.size());
|
|
||||||
assertEquals(Role.USER, roles.iterator().next());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test(expected = AccountException.class)
|
|
||||||
public void testFailedAuthentication()
|
|
||||||
{
|
|
||||||
User trillian = createSampleUser();
|
|
||||||
ScmRealm realm = createRealm(trillian);
|
|
||||||
|
|
||||||
realm.getAuthenticationInfo(token(trillian.getId(), "hobbo"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testSimpleAuthentication()
|
|
||||||
{
|
|
||||||
User trillian = createSampleUser();
|
|
||||||
|
|
||||||
//J-
|
|
||||||
ScmRealm realm = createRealm(
|
|
||||||
trillian,
|
|
||||||
ImmutableSet.of("g1", "g2"),
|
|
||||||
ImmutableSet.of(new Group("xml", "g3"), new Group("xml", "g4")),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
//J+
|
|
||||||
AuthenticationInfo ai = realm.getAuthenticationInfo(token(trillian));
|
|
||||||
|
|
||||||
assertNotNull(ai);
|
|
||||||
|
|
||||||
PrincipalCollection collection = ai.getPrincipals();
|
|
||||||
|
|
||||||
assertNotNull(collection);
|
|
||||||
assertFalse(collection.isEmpty());
|
|
||||||
|
|
||||||
assertEquals(trillian.getId(), collection.getPrimaryPrincipal());
|
|
||||||
assertEquals(trillian, collection.oneByType(User.class));
|
|
||||||
|
|
||||||
GroupNames groups = collection.oneByType(GroupNames.class);
|
|
||||||
|
|
||||||
assertNotNull(groups);
|
|
||||||
assertFalse(groups.getCollection().isEmpty());
|
|
||||||
assertEquals(5, groups.getCollection().size());
|
|
||||||
//J-
|
|
||||||
assertThat(groups,
|
|
||||||
containsInAnyOrder("g1", "g2", "g3", "g4", GroupNames.AUTHENTICATED)
|
|
||||||
);
|
|
||||||
//J+
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private AuthorizationInfo authorizationInfo(User user)
|
|
||||||
{
|
|
||||||
ScmRealm realm = createRealm(user);
|
|
||||||
AuthenticationInfo aui = realm.getAuthenticationInfo(token(user));
|
|
||||||
AuthorizationInfo aci = realm.doGetAuthorizationInfo(aui.getPrincipals());
|
|
||||||
|
|
||||||
assertNotNull(aci);
|
|
||||||
|
|
||||||
return aci;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param permissions
|
|
||||||
* @param repository
|
|
||||||
* @param type
|
|
||||||
*/
|
|
||||||
private void containPermission(Collection<Permission> permissions,
|
|
||||||
Repository repository, PermissionType type)
|
|
||||||
{
|
|
||||||
assertTrue(
|
|
||||||
permissions.contains(new RepositoryPermission(repository.getId(), type)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private ScmRealm createRealm(User user)
|
|
||||||
{
|
|
||||||
return createRealm(user, null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param authenticationGroups
|
|
||||||
* @param dbGroups
|
|
||||||
* @param repositories
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private ScmRealm createRealm(User user,
|
|
||||||
Collection<String> authenticationGroups, Collection<Group> dbGroups,
|
|
||||||
Collection<Repository> repositories)
|
|
||||||
{
|
|
||||||
UserManager userManager = mock(UserManager.class);
|
|
||||||
GroupManager groupManager = mock(GroupManager.class);
|
|
||||||
|
|
||||||
if (dbGroups != null)
|
|
||||||
{
|
|
||||||
when(groupManager.getGroupsForMember(user.getId())).thenReturn(dbGroups);
|
|
||||||
}
|
|
||||||
|
|
||||||
RepositoryDAO repositoryDAO = mock(RepositoryDAO.class);
|
|
||||||
|
|
||||||
if (repositories != null)
|
|
||||||
{
|
|
||||||
when(repositoryDAO.getAll()).thenReturn(repositories);
|
|
||||||
}
|
|
||||||
|
|
||||||
UserDAO userDAO = mock(UserDAO.class);
|
|
||||||
|
|
||||||
when(userDAO.get(user.getId())).thenReturn(user);
|
|
||||||
|
|
||||||
HttpSession session = mock(HttpSession.class);
|
|
||||||
|
|
||||||
final HttpServletRequest request = mock(HttpServletRequest.class);
|
|
||||||
|
|
||||||
when(request.getSession(true)).thenReturn(session);
|
|
||||||
|
|
||||||
Provider<HttpServletRequest> requestProvider =
|
|
||||||
new Provider<HttpServletRequest>()
|
|
||||||
{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpServletRequest get()
|
|
||||||
{
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final HttpServletResponse response = mock(HttpServletResponse.class);
|
|
||||||
Provider<HttpServletResponse> responseProvider =
|
|
||||||
new Provider<HttpServletResponse>()
|
|
||||||
{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpServletResponse get()
|
|
||||||
{
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//J-
|
|
||||||
AuthenticationManager authManager = mock(AuthenticationManager.class);
|
|
||||||
|
|
||||||
when(
|
|
||||||
authManager.authenticate(
|
|
||||||
eq(requestProvider.get()),
|
|
||||||
eq(responseProvider.get()),
|
|
||||||
eq(user.getId()),
|
|
||||||
eq(user.getPassword())
|
|
||||||
)
|
|
||||||
).thenReturn(
|
|
||||||
new AuthenticationResult(user, authenticationGroups, AuthenticationState.SUCCESS)
|
|
||||||
);
|
|
||||||
|
|
||||||
when(
|
|
||||||
authManager.authenticate(
|
|
||||||
eq(requestProvider.get()),
|
|
||||||
eq(responseProvider.get()),
|
|
||||||
eq(user.getId()),
|
|
||||||
argThat(
|
|
||||||
not(user.getPassword())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).thenReturn(
|
|
||||||
AuthenticationResult.FAILED
|
|
||||||
);
|
|
||||||
|
|
||||||
when(
|
|
||||||
authManager.authenticate(
|
|
||||||
eq(requestProvider.get()),
|
|
||||||
eq(responseProvider.get()),
|
|
||||||
argThat(
|
|
||||||
not(user.getName())
|
|
||||||
),
|
|
||||||
anyString()
|
|
||||||
)
|
|
||||||
).thenReturn(
|
|
||||||
AuthenticationResult.NOT_FOUND
|
|
||||||
);
|
|
||||||
|
|
||||||
SecuritySystem securitySystem = mock(SecuritySystem.class);
|
|
||||||
when(
|
|
||||||
securitySystem.getPermissions(Mockito.any(Predicate.class))
|
|
||||||
).thenReturn(
|
|
||||||
Collections.EMPTY_LIST
|
|
||||||
);
|
|
||||||
|
|
||||||
CacheManager cacheManager = new MapCacheManager();
|
|
||||||
|
|
||||||
AuthorizationCollector collector = new AuthorizationCollector(
|
|
||||||
cacheManager,
|
|
||||||
repositoryDAO,
|
|
||||||
securitySystem,
|
|
||||||
new RepositoryPermissionResolver()
|
|
||||||
);
|
|
||||||
|
|
||||||
LoginAttemptHandler dummyLoginAttemptHandler = new LoginAttemptHandler()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void beforeAuthentication(AuthenticationToken token)
|
|
||||||
throws AuthenticationException {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSuccessfulAuthentication(AuthenticationToken token,
|
|
||||||
AuthenticationResult result) throws AuthenticationException {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUnsuccessfulAuthentication(AuthenticationToken token,
|
|
||||||
AuthenticationResult result) throws AuthenticationException {}
|
|
||||||
};
|
|
||||||
|
|
||||||
return new ScmRealm(
|
|
||||||
new ScmConfiguration(),
|
|
||||||
dummyLoginAttemptHandler,
|
|
||||||
collector,
|
|
||||||
// cacheManager,
|
|
||||||
userManager,
|
|
||||||
groupManager,
|
|
||||||
userDAO,
|
|
||||||
authManager,
|
|
||||||
null,
|
|
||||||
requestProvider,
|
|
||||||
responseProvider
|
|
||||||
);
|
|
||||||
//J+
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private User createSampleUser()
|
|
||||||
{
|
|
||||||
User trillian = UserTestData.createTrillian();
|
|
||||||
|
|
||||||
trillian.setPassword("moppo123");
|
|
||||||
|
|
||||||
return trillian;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private String id()
|
|
||||||
{
|
|
||||||
return String.valueOf(counter.incrementAndGet());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param repository
|
|
||||||
* @param user
|
|
||||||
* @param type
|
|
||||||
*/
|
|
||||||
private void prepareRepo(Repository repository, User user,
|
|
||||||
PermissionType type)
|
|
||||||
{
|
|
||||||
prepareRepo(repository, user.getId(), type, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param repository
|
|
||||||
* @param group
|
|
||||||
* @param type
|
|
||||||
*/
|
|
||||||
private void prepareRepo(Repository repository, Group group,
|
|
||||||
PermissionType type)
|
|
||||||
{
|
|
||||||
prepareRepo(repository, group.getId(), type, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param repository
|
|
||||||
* @param name
|
|
||||||
* @param type
|
|
||||||
* @param groupPermission
|
|
||||||
*/
|
|
||||||
private void prepareRepo(Repository repository, String name,
|
|
||||||
PermissionType type, boolean groupPermission)
|
|
||||||
{
|
|
||||||
repository.setId(id());
|
|
||||||
|
|
||||||
List<sonia.scm.repository.Permission> permissions =
|
|
||||||
ImmutableList.of(new sonia.scm.repository.Permission(name, type,
|
|
||||||
groupPermission));
|
|
||||||
|
|
||||||
repository.setPermissions(permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private AuthenticationToken token(User user)
|
|
||||||
{
|
|
||||||
return new UsernamePasswordToken(user.getId(), user.getPassword());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param username
|
|
||||||
* @param password
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private AuthenticationToken token(String username, String password)
|
|
||||||
{
|
|
||||||
return new UsernamePasswordToken(username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private AtomicLong counter = new AtomicLong();
|
|
||||||
}
|
|
||||||
@@ -1,384 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.web.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import sonia.scm.AbstractTestBase;
|
|
||||||
import sonia.scm.SCMContextProvider;
|
|
||||||
import sonia.scm.cache.MapCacheManager;
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
|
||||||
import sonia.scm.security.MessageDigestEncryptionHandler;
|
|
||||||
import sonia.scm.user.User;
|
|
||||||
import sonia.scm.user.UserManager;
|
|
||||||
import sonia.scm.user.UserTestData;
|
|
||||||
import sonia.scm.util.MockUtil;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public class ChainAuthenticationManagerTest extends AbstractTestBase
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthenticateFailed()
|
|
||||||
{
|
|
||||||
manager = createManager();
|
|
||||||
|
|
||||||
AuthenticationResult result = manager.authenticate(request, response,
|
|
||||||
trillian.getName(), "trillian");
|
|
||||||
|
|
||||||
assertNull(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthenticateNotFound()
|
|
||||||
{
|
|
||||||
manager = createManager();
|
|
||||||
|
|
||||||
AuthenticationResult result = manager.authenticate(request, response,
|
|
||||||
"dent", "trillian");
|
|
||||||
|
|
||||||
assertNull(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthenticateSuccess()
|
|
||||||
{
|
|
||||||
manager = createManager();
|
|
||||||
|
|
||||||
AuthenticationResult result = manager.authenticate(request, response,
|
|
||||||
trillian.getName(), "trillian123");
|
|
||||||
|
|
||||||
assertNotNull(result);
|
|
||||||
assertUserEquals(trillian, result.getUser());
|
|
||||||
assertEquals("trilliansType", result.getUser().getType());
|
|
||||||
result = manager.authenticate(request, response, perfect.getName(),
|
|
||||||
"perfect123");
|
|
||||||
assertNotNull(perfect);
|
|
||||||
assertUserEquals(perfect, result.getUser());
|
|
||||||
assertEquals("perfectsType", result.getUser().getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthenticationOrder()
|
|
||||||
{
|
|
||||||
User trillian = UserTestData.createTrillian();
|
|
||||||
|
|
||||||
trillian.setPassword("trillian123");
|
|
||||||
|
|
||||||
SingleUserAuthenticaionHandler a1 =
|
|
||||||
new SingleUserAuthenticaionHandler("a1", trillian);
|
|
||||||
SingleUserAuthenticaionHandler a2 =
|
|
||||||
new SingleUserAuthenticaionHandler("a2", trillian);
|
|
||||||
|
|
||||||
manager = createManager("a2", false, a1, a2);
|
|
||||||
|
|
||||||
AuthenticationResult result = manager.authenticate(request, response,
|
|
||||||
trillian.getName(), "trillian123");
|
|
||||||
|
|
||||||
assertNotNull(result);
|
|
||||||
assertEquals(AuthenticationState.SUCCESS, result.getState());
|
|
||||||
assertEquals("a2", result.getUser().getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testStopChain()
|
|
||||||
{
|
|
||||||
ChainAuthenticatonManager cam = createManager("", false);
|
|
||||||
|
|
||||||
assertTrue(cam.stopChain(new AuthenticationResult(perfect)));
|
|
||||||
assertTrue(cam.stopChain(AuthenticationResult.FAILED));
|
|
||||||
assertFalse(cam.stopChain(AuthenticationResult.NOT_FOUND));
|
|
||||||
cam = createManager("", true);
|
|
||||||
assertTrue(cam.stopChain(new AuthenticationResult(perfect)));
|
|
||||||
assertFalse(cam.stopChain(AuthenticationResult.FAILED));
|
|
||||||
assertFalse(cam.stopChain(AuthenticationResult.NOT_FOUND));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void postSetUp() throws Exception
|
|
||||||
{
|
|
||||||
request = MockUtil.getHttpServletRequest();
|
|
||||||
response = MockUtil.getHttpServletResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void preTearDown() throws Exception
|
|
||||||
{
|
|
||||||
manager.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param other
|
|
||||||
*/
|
|
||||||
private void assertUserEquals(User user, User other)
|
|
||||||
{
|
|
||||||
assertEquals(user.getName(), other.getName());
|
|
||||||
assertEquals(user.getDisplayName(), other.getDisplayName());
|
|
||||||
assertEquals(user.getMail(), other.getMail());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private ChainAuthenticatonManager createManager()
|
|
||||||
{
|
|
||||||
perfect = UserTestData.createPerfect();
|
|
||||||
perfect.setPassword("perfect123");
|
|
||||||
trillian = UserTestData.createTrillian();
|
|
||||||
trillian.setPassword("trillian123");
|
|
||||||
|
|
||||||
return createManager("", false,
|
|
||||||
new SingleUserAuthenticaionHandler("perfectsType", perfect),
|
|
||||||
new SingleUserAuthenticaionHandler("trilliansType", trillian));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param defaultType
|
|
||||||
* @param skipFailedAuthenticators
|
|
||||||
* @param handlers
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private ChainAuthenticatonManager createManager(String defaultType,
|
|
||||||
boolean skipFailedAuthenticators, AuthenticationHandler... handlers)
|
|
||||||
{
|
|
||||||
if ( handlers == null || handlers.length == 0 ){
|
|
||||||
//J-
|
|
||||||
handlers = new AuthenticationHandler[]{
|
|
||||||
new SingleUserAuthenticaionHandler("perfectsType", perfect),
|
|
||||||
new SingleUserAuthenticaionHandler("trilliansType", trillian)
|
|
||||||
};
|
|
||||||
//J+
|
|
||||||
}
|
|
||||||
ScmConfiguration configuration = new ScmConfiguration();
|
|
||||||
|
|
||||||
configuration.setSkipFailedAuthenticators(skipFailedAuthenticators);
|
|
||||||
|
|
||||||
Set<AuthenticationHandler> handlerSet = ImmutableSet.copyOf(handlers);
|
|
||||||
|
|
||||||
UserManager userManager = mock(UserManager.class);
|
|
||||||
|
|
||||||
when(userManager.getDefaultType()).thenReturn(defaultType);
|
|
||||||
manager = new ChainAuthenticatonManager(configuration, userManager,
|
|
||||||
handlerSet, new MessageDigestEncryptionHandler(), new MapCacheManager());
|
|
||||||
manager.init(contextProvider);
|
|
||||||
|
|
||||||
return manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- inner classes --------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @version Enter version here..., 2010-12-07
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
private static class SingleUserAuthenticaionHandler
|
|
||||||
implements AuthenticationHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param type
|
|
||||||
* @param user
|
|
||||||
*/
|
|
||||||
public SingleUserAuthenticaionHandler(String type, User user)
|
|
||||||
{
|
|
||||||
this.type = type;
|
|
||||||
this.user = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods ------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @param username
|
|
||||||
* @param password
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public AuthenticationResult authenticate(HttpServletRequest request,
|
|
||||||
HttpServletResponse response, String username, String password)
|
|
||||||
{
|
|
||||||
AuthenticationResult result = null;
|
|
||||||
|
|
||||||
if (username.equals(user.getName()))
|
|
||||||
{
|
|
||||||
if (password.equals(user.getPassword()))
|
|
||||||
{
|
|
||||||
result = new AuthenticationResult(user.clone());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = AuthenticationResult.FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = AuthenticationResult.NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void init(SCMContextProvider context) {}
|
|
||||||
|
|
||||||
//~--- get methods --------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getType()
|
|
||||||
{
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields -------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final String type;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final User user;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private ChainAuthenticatonManager manager;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private User perfect;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private HttpServletRequest request;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private HttpServletResponse response;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private User trillian;
|
|
||||||
}
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.web.security;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import sonia.scm.AbstractTestBase;
|
|
||||||
import sonia.scm.security.EncryptionHandler;
|
|
||||||
import sonia.scm.security.MessageDigestEncryptionHandler;
|
|
||||||
import sonia.scm.store.JAXBStoreFactory;
|
|
||||||
import sonia.scm.store.StoreFactory;
|
|
||||||
import sonia.scm.user.DefaultUserManager;
|
|
||||||
import sonia.scm.user.User;
|
|
||||||
import sonia.scm.user.UserTestData;
|
|
||||||
import sonia.scm.user.xml.XmlUserDAO;
|
|
||||||
import sonia.scm.util.MockUtil;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public class DefaultAuthenticationHandlerTest extends AbstractTestBase
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthenticateFailed()
|
|
||||||
{
|
|
||||||
AuthenticationResult result = handler.authenticate(request, reponse,
|
|
||||||
slarti.getName(), "otherPWD");
|
|
||||||
|
|
||||||
assertNotNull(result);
|
|
||||||
assertTrue(result.getState() == AuthenticationState.FAILED);
|
|
||||||
assertNull(result.getUser());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthenticateNotFound()
|
|
||||||
{
|
|
||||||
AuthenticationResult result = handler.authenticate(request, reponse,
|
|
||||||
"notSlarti", "otherPWD");
|
|
||||||
|
|
||||||
assertNotNull(result);
|
|
||||||
assertTrue(result.getState() == AuthenticationState.NOT_FOUND);
|
|
||||||
assertNull(result.getUser());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthenticateSuccess()
|
|
||||||
{
|
|
||||||
AuthenticationResult result = handler.authenticate(request, reponse,
|
|
||||||
slarti.getName(), "slartisPWD");
|
|
||||||
|
|
||||||
assertNotNull(result);
|
|
||||||
assertTrue(result.getState() == AuthenticationState.SUCCESS);
|
|
||||||
assertNotNull(result.getUser());
|
|
||||||
assertEquals(slarti.getName(), result.getUser().getName());
|
|
||||||
assertEquals(slarti.getDisplayName(), result.getUser().getDisplayName());
|
|
||||||
assertEquals(slarti.getMail(), result.getUser().getMail());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void postSetUp() throws Exception
|
|
||||||
{
|
|
||||||
EncryptionHandler enc = new MessageDigestEncryptionHandler();
|
|
||||||
|
|
||||||
slarti = UserTestData.createSlarti();
|
|
||||||
slarti.setPassword(enc.encrypt("slartisPWD"));
|
|
||||||
|
|
||||||
StoreFactory storeFactory = new JAXBStoreFactory();
|
|
||||||
|
|
||||||
storeFactory.init(contextProvider);
|
|
||||||
|
|
||||||
XmlUserDAO userDAO = new XmlUserDAO(storeFactory);
|
|
||||||
|
|
||||||
setSubject(MockUtil.createAdminSubject());
|
|
||||||
|
|
||||||
DefaultUserManager userManager = new DefaultUserManager(userDAO);
|
|
||||||
|
|
||||||
userManager.init(contextProvider);
|
|
||||||
userManager.create(slarti);
|
|
||||||
clearSubject();
|
|
||||||
|
|
||||||
handler = new DefaultAuthenticationHandler(userManager, enc);
|
|
||||||
handler.init(contextProvider);
|
|
||||||
request = MockUtil.getHttpServletRequest();
|
|
||||||
reponse = MockUtil.getHttpServletResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void preTearDown() throws Exception
|
|
||||||
{
|
|
||||||
handler.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private DefaultAuthenticationHandler handler;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private HttpServletResponse reponse;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private HttpServletRequest request;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private User slarti;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user