diff --git a/pom.xml b/pom.xml
index a4d1254af4..bd853442bc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -169,6 +169,14 @@
1.0
+
+
+ compile
+
+ check
+
+
+
@@ -438,7 +446,7 @@
1.1.1
2.5
3.0
- 1.18
+ 1.18.1
2.3.20
7.6.14.v20131031
@@ -446,11 +454,11 @@
1.2.0
- 1.2.2
+ 1.2.3
- 3.2.0.201312181205-r
- 1.8.3-scm1
+ 3.3.0.201403021825-r
+ 1.8.4-scm2
16.0
diff --git a/scm-clients/scm-cli-client/pom.xml b/scm-clients/scm-cli-client/pom.xml
index 8fd5d37daf..65b9e1273e 100644
--- a/scm-clients/scm-cli-client/pom.xml
+++ b/scm-clients/scm-cli-client/pom.xml
@@ -41,7 +41,7 @@
args4j
args4j
- 2.0.25
+ 2.0.26
diff --git a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/cmd/GetRepositorySubCommand.java b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/cmd/GetRepositorySubCommand.java
index c7c497bacf..2e8227fa60 100644
--- a/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/cmd/GetRepositorySubCommand.java
+++ b/scm-clients/scm-cli-client/src/main/java/sonia/scm/cli/cmd/GetRepositorySubCommand.java
@@ -98,7 +98,22 @@ public class GetRepositorySubCommand extends TemplateSubCommand
protected void run()
{
ScmClientSession session = createSession();
- Repository repository = session.getRepositoryHandler().get(id);
+
+ Repository repository;
+
+ int index = id.indexOf("/");
+
+ if (index > 0)
+ {
+ String type = id.substring(0, index);
+ String name = id.substring(index + 1);
+
+ repository = session.getRepositoryHandler().get(type, name);
+ }
+ else
+ {
+ repository = session.getRepositoryHandler().get(id);
+ }
if (repository != null)
{
@@ -117,7 +132,7 @@ public class GetRepositorySubCommand extends TemplateSubCommand
/** Field description */
@Argument(
- usage = "optionRepositoryId",
+ usage = "optionRepositoryIdOrTypeAndName",
metaVar = "repositoryid",
required = true
)
diff --git a/scm-clients/scm-cli-client/src/main/resources/sonia/resources/i18n.properties b/scm-clients/scm-cli-client/src/main/resources/sonia/resources/i18n.properties
index e80757638b..d5c707f090 100644
--- a/scm-clients/scm-cli-client/src/main/resources/sonia/resources/i18n.properties
+++ b/scm-clients/scm-cli-client/src/main/resources/sonia/resources/i18n.properties
@@ -44,6 +44,7 @@ optionLoggingLevel = Logging level (DEBUG, INFO, WARN, ERROR)
optionTemplate = Template
optionTemplateFile = Template file
optionRepositoryId = Repository Id
+optionRepositoryIdOrTypeAndName = Repository Id or type/name
optionRepositoryName = Repository name
optionRepositoryType = Repository name
optionRepositoryContact = Repository contact
@@ -56,7 +57,7 @@ optionPermissionName = Group or user name
optionPermissionType = Permission type (READ,WRITE or OWNER)
optionUserName = Username
-optionUserDisplayName = "Diesplay name
+optionUserDisplayName = Display name
optionUserMail = E-Mail address
optionUserPassword = Password
optionUserType = Type
diff --git a/scm-core/src/main/java/sonia/scm/ClientMessages.java b/scm-core/src/main/java/sonia/scm/ClientMessages.java
new file mode 100644
index 0000000000..d03bb34fad
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/ClientMessages.java
@@ -0,0 +1,103 @@
+/**
+ * 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;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import javax.servlet.http.HttpServletRequest;
+import sonia.scm.i18n.I18nMessages;
+
+//~--- JDK imports ------------------------------------------------------------
+
+
+/**
+ * I18n messages which are send back to client.
+ *
+ * @author Sebastian Sdorra
+ * @since 1.37
+ */
+public final class ClientMessages
+{
+
+ /**
+ * Constructs a new instance of ClientMessages. This constructor should not be
+ * used. Use the {@link #get(javax.servlet.http.HttpServletRequest)} method
+ * instead.
+ */
+ public ClientMessages() {}
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Returns the localized string for a failed authentication.
+ *
+ *
+ * @return localized string
+ */
+ public String failedAuthentication()
+ {
+ return failedAuthentication;
+ }
+
+ /**
+ * Returns the localized string for "not enough privileges.
+ *
+ *
+ * @return localized string
+ */
+ public String notEnoughPrivileges()
+ {
+ return notEnoughPrivileges;
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Returns an instance {@link ClientMessages}.
+ *
+ * @param request servlet request
+ *
+ * @return instance of client messages
+ */
+ public static ClientMessages get(HttpServletRequest request)
+ {
+ return I18nMessages.get(ClientMessages.class, request);
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** failed authentication */
+ private String failedAuthentication;
+
+ /** not enough privileges */
+ private String notEnoughPrivileges;
+}
diff --git a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java
index 338424d824..6163cd7ff2 100644
--- a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java
+++ b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java
@@ -295,6 +295,7 @@ public class ScmConfiguration
*
*
* @return realm description
+ * @since 1.36
*/
public String getRealmDescription()
{
@@ -577,6 +578,7 @@ public class ScmConfiguration
*
*
* @param realmDescription
+ * @since 1.36
*/
public void setRealmDescription(String realmDescription)
{
diff --git a/scm-core/src/main/java/sonia/scm/i18n/Bundle.java b/scm-core/src/main/java/sonia/scm/i18n/Bundle.java
index be349fddb7..515ced9ef8 100644
--- a/scm-core/src/main/java/sonia/scm/i18n/Bundle.java
+++ b/scm-core/src/main/java/sonia/scm/i18n/Bundle.java
@@ -30,10 +30,12 @@
*/
+
package sonia.scm.i18n;
//~--- non-JDK imports --------------------------------------------------------
+import sonia.scm.util.ClassLoaders;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
@@ -41,6 +43,7 @@ import sonia.scm.util.Util;
import java.text.MessageFormat;
import java.util.Locale;
+import java.util.MissingResourceException;
import java.util.ResourceBundle;
/**
@@ -81,7 +84,7 @@ public class Bundle
*/
public static Bundle getBundle(String path)
{
- return new Bundle(ResourceBundle.getBundle(path));
+ return getBundle(path, null, null);
}
/**
@@ -95,7 +98,35 @@ public class Bundle
*/
public static Bundle getBundle(String path, Locale locale)
{
- return new Bundle(ResourceBundle.getBundle(path, locale));
+ return getBundle(path, locale, null);
+ }
+
+ /**
+ * Creates a new bundle instance
+ *
+ *
+ * @param path path to the properties file
+ * @param locale locale for the properties file
+ * @param classLoader classLoader to load
+ *
+ * @return new bundle instance
+ *
+ * @since 1.37
+ */
+ public static Bundle getBundle(String path, Locale locale,
+ ClassLoader classLoader)
+ {
+ if (locale == null)
+ {
+ locale = Locale.ENGLISH;
+ }
+
+ if (classLoader == null)
+ {
+ classLoader = ClassLoaders.getContextClassLoader(Bundle.class);
+ }
+
+ return new Bundle(ResourceBundle.getBundle(path, locale, classLoader));
}
/**
@@ -134,8 +165,33 @@ public class Bundle
return msg;
}
+ /**
+ * Returns the value of the key, formatted with {@link MessageFormat} or null
+ * if the key is not present in the bundle.
+ *
+ *
+ * @param key key in the properties file
+ * @param args format arguments
+ *
+ * @return formated message or null
+ *
+ * @since 1.37
+ */
+ public String getStringIfPresent(String key, Object... args)
+ {
+ String msg = null;
+
+ try
+ {
+ msg = getString(key, args);
+ }
+ catch (MissingResourceException ex) {}
+
+ return msg;
+ }
+
//~--- fields ---------------------------------------------------------------
- /** Field description */
- private ResourceBundle bundle;
+ /** resource bundle */
+ private final ResourceBundle bundle;
}
diff --git a/scm-core/src/main/java/sonia/scm/i18n/I18n.java b/scm-core/src/main/java/sonia/scm/i18n/I18n.java
new file mode 100644
index 0000000000..63d761fb17
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/i18n/I18n.java
@@ -0,0 +1,60 @@
+/**
+ * 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.i18n;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The I18n annotation is used by the {@link I18nMessages} class to define the
+ * resource bundle key.
+ *
+ * @author Sebastian Sdorra
+ * @since 1.37
+ */
+@Documented
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface I18n
+{
+ /**
+ * Returns the key for the resource bundle.
+ *
+ * @return resource bundle key
+ */
+ String value();
+}
diff --git a/scm-core/src/main/java/sonia/scm/i18n/I18nException.java b/scm-core/src/main/java/sonia/scm/i18n/I18nException.java
new file mode 100644
index 0000000000..dc7d062de7
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/i18n/I18nException.java
@@ -0,0 +1,85 @@
+/**
+ * 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.i18n;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class I18nException extends RuntimeException
+{
+
+ /** Field description */
+ private static final long serialVersionUID = 1845326427312983227L;
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ */
+ public I18nException() {}
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param message
+ */
+ public I18nException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param cause
+ */
+ public I18nException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param message
+ * @param cause
+ */
+ public I18nException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+}
diff --git a/scm-core/src/main/java/sonia/scm/i18n/I18nMessages.java b/scm-core/src/main/java/sonia/scm/i18n/I18nMessages.java
new file mode 100644
index 0000000000..0c11066f82
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/i18n/I18nMessages.java
@@ -0,0 +1,288 @@
+/**
+ * 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.i18n;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.common.base.Objects;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
+import sonia.scm.util.ClassLoaders;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.lang.reflect.Field;
+
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * The I18nMessages class instantiates a class and initializes all {@link String}
+ * fields with values from a resource bundle. The resource bundle must have the
+ * same name as the class. Each field which should be initialized from the
+ * bundle, must match a key in the resource bundle or is annotated with a
+ * {@link I18n} annotation which holds the key. I18nMessages injects also the
+ * locale and the bundle if it founds a field with the corresponding type.
+ *
+ * @author Sebastian Sdorra
+ * @since 1.37
+ */
+public final class I18nMessages
+{
+
+ /** Field description */
+ private static final Cache cache =
+ CacheBuilder.newBuilder().build();
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ */
+ private I18nMessages() {}
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Same as {@link #get(java.lang.Class, java.util.Locale)}, with locale
+ * {@link Locale#ENGLISH}.
+ *
+ * @param msgClass message class
+ * @param type of message class
+ *
+ * @return instance of message class
+ */
+ public static T get(Class msgClass)
+ {
+ return get(msgClass, Locale.ENGLISH);
+ }
+
+ /**
+ * Same as {@link #get(java.lang.Class, java.util.Locale)}, with locale
+ * from servlet request ({@link HttpServletRequest#getLocale()}).
+ *
+ *
+ * @param msgClass message class
+ * @param request servlet request
+ * @param type of message class
+ *
+ * @return
+ */
+ public static T get(Class msgClass, HttpServletRequest request)
+ {
+ return get(msgClass, request.getLocale());
+ }
+
+ /**
+ * Returns a instance of the given message class with all message fields
+ * initialized.
+ *
+ *
+ * @param msgClass message class
+ * @param locale locale
+ * @param type of the message class
+ *
+ * @return instance of message class
+ */
+ public synchronized static T get(Class msgClass, Locale locale)
+ {
+ CacheKey ck = new CacheKey(locale, msgClass);
+ T instance = (T) cache.getIfPresent(ck);
+
+ if (instance == null)
+ {
+ instance = createInstance(msgClass, locale);
+ cache.put(ck, instance);
+ }
+
+ return instance;
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param msgClass
+ * @param locale
+ * @param
+ *
+ * @return
+ */
+ private static T createInstance(Class msgClass, Locale locale)
+ {
+ Bundle bundle = Bundle.getBundle(msgClass.getName(), locale,
+ ClassLoaders.getContextClassLoader(msgClass));
+ T instance = null;
+
+ try
+ {
+ instance = msgClass.newInstance();
+ initializeInstance(bundle, locale, msgClass, instance);
+ }
+ catch (Exception ex)
+ {
+ throw new I18nException("could not instantiate/initialize class", ex);
+ }
+
+ return instance;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param bundle
+ * @param locale
+ * @param msgClass
+ * @param instance
+ *
+ * @throws IllegalAccessException
+ * @throws IllegalArgumentException
+ */
+ private static void initializeInstance(Bundle bundle, Locale locale,
+ Class msgClass, Object instance)
+ throws IllegalArgumentException, IllegalAccessException
+ {
+ for (Field field : msgClass.getDeclaredFields())
+ {
+ if (field.getType().isAssignableFrom(String.class))
+ {
+ String key = field.getName();
+ I18n i18n = field.getAnnotation(I18n.class);
+
+ if (i18n != null)
+ {
+ key = i18n.value();
+ }
+
+ String value = bundle.getString(key);
+
+ if (value != null)
+ {
+ field.setAccessible(true);
+ field.set(instance, value);
+ }
+ }
+ else if (field.getType().isAssignableFrom(Bundle.class))
+ {
+ field.setAccessible(true);
+ field.set(instance, bundle);
+ }
+ else if (field.getType().isAssignableFrom(Locale.class))
+ {
+
+ field.setAccessible(true);
+ field.set(instance, locale);
+ }
+ }
+ }
+
+ //~--- inner classes --------------------------------------------------------
+
+ /**
+ * Class description
+ *
+ *
+ * @version Enter version here..., 14/03/15
+ * @author Enter your name here...
+ */
+ private static class CacheKey
+ {
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param locale
+ * @param msgClass
+ */
+ public CacheKey(Locale locale, Class msgClass)
+ {
+ this.locale = locale;
+ this.msgClass = msgClass;
+ }
+
+ //~--- methods ------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param obj
+ *
+ * @return
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+
+ final CacheKey other = (CacheKey) obj;
+
+ return Objects.equal(locale, other.locale)
+ && Objects.equal(msgClass, other.msgClass);
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public int hashCode()
+ {
+ return Objects.hashCode(locale, msgClass);
+ }
+
+ //~--- fields -------------------------------------------------------------
+
+ /** Field description */
+ private final Locale locale;
+
+ /** Field description */
+ private final Class msgClass;
+ }
+}
diff --git a/scm-core/src/main/java/sonia/scm/io/DeepCopy.java b/scm-core/src/main/java/sonia/scm/io/DeepCopy.java
index a7d5a31bbe..3a5a1675d0 100644
--- a/scm-core/src/main/java/sonia/scm/io/DeepCopy.java
+++ b/scm-core/src/main/java/sonia/scm/io/DeepCopy.java
@@ -30,8 +30,13 @@
*/
+
package sonia.scm.io;
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.common.io.Closer;
+
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
@@ -70,12 +75,15 @@ public final class DeepCopy
{
T obj = null;
+ Closer closer = Closer.create();
+
try
{
// Write the object out to a byte array
- FastByteArrayOutputStream fbos = new FastByteArrayOutputStream();
- ObjectOutputStream out = new ObjectOutputStream(fbos);
+ FastByteArrayOutputStream fbos =
+ closer.register(new FastByteArrayOutputStream());
+ ObjectOutputStream out = closer.register(new ObjectOutputStream(fbos));
out.writeObject(orig);
out.flush();
@@ -83,7 +91,10 @@ public final class DeepCopy
// Retrieve an input stream from the byte array and read
// a copy of the object back in.
- ObjectInputStream in = new ObjectInputStream(fbos.getInputStream());
+ // use ScmObjectInputStream to solve ClassNotFoundException
+ // for plugin classes
+ ObjectInputStream in =
+ closer.register(new ScmObjectInputStream(fbos.getInputStream()));
obj = (T) in.readObject();
}
@@ -91,6 +102,10 @@ public final class DeepCopy
{
throw new IOException("could not copy object", ex);
}
+ finally
+ {
+ closer.close();
+ }
return obj;
}
diff --git a/scm-core/src/main/java/sonia/scm/io/ScmObjectInputStream.java b/scm-core/src/main/java/sonia/scm/io/ScmObjectInputStream.java
new file mode 100644
index 0000000000..a8ec919adf
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/io/ScmObjectInputStream.java
@@ -0,0 +1,124 @@
+/**
+ * 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.io;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+
+/**
+ * {@link ObjectInputStream} implementation which uses the context class loader
+ * to resolve classes.
+ *
+ * @author Sebastian Sdorra
+ * @since 1.36
+ */
+public class ScmObjectInputStream extends ObjectInputStream
+{
+
+ /**
+ * the logger for ScmObjectInputStream
+ */
+ private static final Logger logger =
+ LoggerFactory.getLogger(ScmObjectInputStream.class);
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * {@inheritDoc}
+ */
+ public ScmObjectInputStream(InputStream stream) throws IOException
+ {
+ super(stream);
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Class> resolveClass(ObjectStreamClass desc)
+ throws IOException, ClassNotFoundException
+ {
+ Class> clazz = null;
+ ClassLoader classLoader = getClassLoader();
+
+ try
+ {
+ clazz = classLoader.loadClass(desc.getName());
+ }
+ catch (ClassNotFoundException ex)
+ {
+ // do not log the exception, because the class
+ // is mostly found by the parent method.
+ }
+
+ if (clazz == null)
+ {
+ clazz = super.resolveClass(desc);
+ }
+
+ return clazz;
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Returns the context class loader if available. If the context class loader
+ * is not available the method will fall back to the class loader which has
+ * load this class.
+ *
+ *
+ * @return context class loader or default class loader
+ */
+ private ClassLoader getClassLoader()
+ {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
+ if (classLoader == null)
+ {
+ logger.debug("could not find context class loader, fall back to default");
+ classLoader = ScmObjectInputStream.class.getClassLoader();
+ }
+
+ return classLoader;
+ }
+}
diff --git a/scm-core/src/main/java/sonia/scm/search/SearchUtil.java b/scm-core/src/main/java/sonia/scm/search/SearchUtil.java
index 81ff258b7a..90c65e3456 100644
--- a/scm-core/src/main/java/sonia/scm/search/SearchUtil.java
+++ b/scm-core/src/main/java/sonia/scm/search/SearchUtil.java
@@ -35,6 +35,9 @@ package sonia.scm.search;
//~--- non-JDK imports --------------------------------------------------------
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import sonia.scm.TransformFilter;
import sonia.scm.util.Util;
@@ -53,6 +56,14 @@ import java.util.Locale;
public final class SearchUtil
{
+ /**
+ * the logger for SearchUtil
+ */
+ private static final Logger logger =
+ LoggerFactory.getLogger(SearchUtil.class);
+
+ //~--- constructors ---------------------------------------------------------
+
/**
* Constructs ...
*
@@ -180,6 +191,77 @@ public final class SearchUtil
return items;
}
+ /**
+ * Method description
+ *
+ *
+ * @param pattern
+ * @param c
+ */
+ private static void appendChar(StringBuilder pattern, char c)
+ {
+ switch (c)
+ {
+ case '*' :
+ pattern.append(".*");
+
+ break;
+
+ case '?' :
+ pattern.append(".");
+
+ break;
+
+ case '(' :
+ pattern.append("\\(");
+
+ break;
+
+ case ')' :
+ pattern.append("\\)");
+
+ break;
+
+ case '{' :
+ pattern.append("\\{");
+
+ break;
+
+ case '}' :
+ pattern.append("\\}");
+
+ break;
+
+ case '[' :
+ pattern.append("\\[");
+
+ break;
+
+ case ']' :
+ pattern.append("\\]");
+
+ break;
+
+ case '|' :
+ pattern.append("\\|");
+
+ break;
+
+ case '.' :
+ pattern.append("\\.");
+
+ break;
+
+ case '\\' :
+ pattern.append("\\\\");
+
+ break;
+
+ default :
+ pattern.append(c);
+ }
+ }
+
/**
* Method description
*
@@ -192,19 +274,26 @@ public final class SearchUtil
{
String query = request.getQuery().trim();
+ StringBuilder pattern = new StringBuilder();
+
if (request.isIgnoreCase())
{
+ pattern.append("(?i)");
query = query.toLowerCase(Locale.ENGLISH);
}
- query = query.replace("\\", "\\\\").replace("*", ".*").replace("?", ".");
- query = ".*".concat(query).concat(".*");
+ pattern.append(".*");
- if (request.isIgnoreCase())
+ for (char c : query.toCharArray())
{
- query = "(?i)".concat(query);
+ appendChar(pattern, c);
}
- return query;
+ pattern.append(".*");
+
+ logger.trace("converted query \"{}\" to regex pattern \"{}\"",
+ request.getQuery(), pattern);
+
+ return pattern.toString();
}
}
diff --git a/scm-core/src/main/java/sonia/scm/util/ClassLoaders.java b/scm-core/src/main/java/sonia/scm/util/ClassLoaders.java
new file mode 100644
index 0000000000..80998ef693
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/util/ClassLoaders.java
@@ -0,0 +1,72 @@
+/**
+ * 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.util;
+
+/**
+ * Util methods for {@link ClassLoader}s.
+ *
+ * @author Sebastian Sdorra
+ * @since 1.37
+ */
+public final class ClassLoaders
+{
+
+ /**
+ * Constructs ...
+ *
+ */
+ private ClassLoaders() {}
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Returns the context {@link ClassLoader} from the current {@link Thread}, if
+ * the context {@link ClassLoader} is not available the {@link ClassLoader},
+ * which has load the given context class, is used.
+ *
+ *
+ * @param contextClass context class
+ *
+ * @return context class loader
+ */
+ public static ClassLoader getContextClassLoader(Class> contextClass)
+ {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
+ if (classLoader == null)
+ {
+ classLoader = contextClass.getClassLoader();
+ }
+
+ return classLoader;
+ }
+}
diff --git a/scm-core/src/main/java/sonia/scm/util/HttpUtil.java b/scm-core/src/main/java/sonia/scm/util/HttpUtil.java
index 69f913d74d..244ac98719 100644
--- a/scm-core/src/main/java/sonia/scm/util/HttpUtil.java
+++ b/scm-core/src/main/java/sonia/scm/util/HttpUtil.java
@@ -37,6 +37,7 @@ package sonia.scm.util;
import com.google.common.base.CharMatcher;
import com.google.common.base.Strings;
+import com.google.common.io.ByteStreams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,11 +47,13 @@ import sonia.scm.config.ScmConfiguration;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
+import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
+import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -77,6 +80,9 @@ public final class HttpUtil
*/
public static final String HEADER_SCM_CLIENT = "X-SCM-Client";
+ /** Field description */
+ public static final String HEADER_USERAGENT = "User-Agent";
+
/** authentication header */
public static final String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
@@ -158,6 +164,9 @@ public final class HttpUtil
public static final String STATUS_UNAUTHORIZED_MESSAGE =
"Authorization Required";
+ /** Field description */
+ private static final int SKIP_SIZE = 4096;
+
/** the logger for HttpUtil */
private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class);
@@ -167,7 +176,7 @@ public final class HttpUtil
*/
private static final Pattern PATTERN_URLNORMALIZE =
Pattern.compile("(?:(http://[^:]+):80(/.+)?|(https://[^:]+):443(/.+)?)");
-
+
/**
* CharMatcher to select cr/lf and '%' characters
* @since 1.28
@@ -197,10 +206,10 @@ public final class HttpUtil
*/
public static String append(String uri, String suffix)
{
- if ( uri.endsWith(SEPARATOR_PATH) && suffix.startsWith(SEPARATOR_PATH) )
+ if (uri.endsWith(SEPARATOR_PATH) && suffix.startsWith(SEPARATOR_PATH))
{
- uri = uri.substring( 0, uri.length() - 1 );
- }
+ uri = uri.substring(0, uri.length() - 1);
+ }
else if (!uri.endsWith(SEPARATOR_PATH) &&!suffix.startsWith(SEPARATOR_PATH))
{
uri = uri.concat(SEPARATOR_PATH);
@@ -299,6 +308,38 @@ public final class HttpUtil
return value;
}
+ /**
+ * Skips to complete body of a request.
+ *
+ *
+ * @param request http request
+ *
+ * @since 1.37
+ */
+ public static void drainBody(HttpServletRequest request)
+ {
+ if (isChunked(request) || (request.getContentLength() > 0))
+ {
+ InputStream in = null;
+
+ try
+ {
+ in = request.getInputStream();
+
+ while ((0 < in.skip(SKIP_SIZE)) || (0 <= in.read()))
+ {
+
+ // nothing
+ }
+ }
+ catch (IOException e) {}
+ finally
+ {
+ IOUtil.close(in);
+ }
+ }
+ }
+
/**
* Method description
*
@@ -443,8 +484,11 @@ public final class HttpUtil
* @param realmDescription - realm description
*
* @throws IOException
+ *
+ * @since 1.36
*/
- public static void sendUnauthorized(HttpServletResponse response, String realmDescription)
+ public static void sendUnauthorized(HttpServletResponse response,
+ String realmDescription)
throws IOException
{
sendUnauthorized(null, response, realmDescription);
@@ -463,8 +507,7 @@ public final class HttpUtil
* @since 1.19
*/
public static void sendUnauthorized(HttpServletRequest request,
- HttpServletResponse response,
- String realmDescription)
+ HttpServletResponse response, String realmDescription)
throws IOException
{
if ((request == null) ||!isWUIRequest(request))
@@ -483,6 +526,26 @@ public final class HttpUtil
STATUS_UNAUTHORIZED_MESSAGE);
}
+ /**
+ * Returns true if the User-Agent header of the current request starts with
+ * the given string.
+ *
+ *
+ * @param request http request
+ * @param userAgent string to test against the header
+ *
+ * @return true if the header starts with the given string
+ *
+ * @since 1.37
+ */
+ public static boolean userAgentStartsWith(HttpServletRequest request,
+ String userAgent)
+ {
+ return Strings.nullToEmpty(request.getHeader(HEADER_USERAGENT)).toLowerCase(
+ Locale.ENGLISH).startsWith(
+ Strings.nullToEmpty(userAgent).toLowerCase(Locale.ENGLISH));
+ }
+
//~--- get methods ----------------------------------------------------------
/**
@@ -669,6 +732,21 @@ public final class HttpUtil
return uri;
}
+ /**
+ * Returns true if the body of the request is chunked.
+ *
+ *
+ * @param request http request
+ *
+ * @return true if the request is chunked
+ *
+ * @since 1.37
+ */
+ public static boolean isChunked(HttpServletRequest request)
+ {
+ return "chunked".equals(request.getHeader("Transfer-Encoding"));
+ }
+
/**
* Returns true if the http request is send by the scm-manager web interface.
*
diff --git a/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java
index 5992fd4cf7..f88e25a961 100644
--- a/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java
+++ b/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java
@@ -35,7 +35,6 @@ package sonia.scm.web.filter;
//~--- non-JDK imports --------------------------------------------------------
-import com.google.common.base.Strings;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -83,6 +82,9 @@ public class BasicAuthenticationFilter extends AutoLoginFilter
/** Field description */
public static final String HEADER_AUTHORIZATION = "Authorization";
+ /** marker for failed authentication */
+ private static final String ATTRIBUTE_FAILED_AUTH = "sonia.scm.auth.failed";
+
/** the logger for BasicAuthenticationFilter */
private static final Logger logger =
LoggerFactory.getLogger(BasicAuthenticationFilter.class);
@@ -182,9 +184,8 @@ public class BasicAuthenticationFilter extends AutoLoginFilter
}
/**
- * Sends status code 401 back to client, if no authorization header was found,
- * if a authorization is present and the authentication failed the method will
- * send status code 403.
+ * Sends status code 403 back to client, if the authentication has failed.
+ * In all other cases the method will send status code 403 back to client.
*
* @param request servlet request
* @param response servlet response
@@ -199,18 +200,53 @@ public class BasicAuthenticationFilter extends AutoLoginFilter
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException
{
- String authentication = request.getHeader(HEADER_AUTHORIZATION);
- if (Strings.isNullOrEmpty(authentication))
+ // send only forbidden, if the authentication has failed.
+ // see https://bitbucket.org/sdorra/scm-manager/issue/545/git-clone-with-username-in-url-does-not
+ if (Boolean.TRUE.equals(request.getAttribute(ATTRIBUTE_FAILED_AUTH)))
{
- HttpUtil.sendUnauthorized(request, response, configuration.getRealmDescription());
+ sendFailedAuthenticationError(request, response);
}
else
{
- response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ sendUnauthorizedError(request, response);
}
}
+ /**
+ * Sends an error for a failed authentication back to client.
+ *
+ *
+ * @param request http request
+ * @param response http response
+ *
+ * @throws IOException
+ */
+ protected void sendFailedAuthenticationError(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException
+ {
+ HttpUtil.sendUnauthorized(request, response,
+ configuration.getRealmDescription());
+ }
+
+ /**
+ * Sends an unauthorized error back to client.
+ *
+ *
+ * @param request http request
+ * @param response http response
+ *
+ * @throws IOException
+ */
+ protected void sendUnauthorizedError(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException
+ {
+ HttpUtil.sendUnauthorized(request, response,
+ configuration.getRealmDescription());
+ }
+
/**
* Method description
*
@@ -254,6 +290,10 @@ public class BasicAuthenticationFilter extends AutoLoginFilter
}
catch (AuthenticationException ex)
{
+
+ // add a marker to the request that the authentication has failed
+ request.setAttribute(ATTRIBUTE_FAILED_AUTH, Boolean.TRUE);
+
if (logger.isTraceEnabled())
{
logger.trace("authentication failed for user ".concat(username),
@@ -280,6 +320,6 @@ public class BasicAuthenticationFilter extends AutoLoginFilter
//~--- fields ---------------------------------------------------------------
- /** Field description */
- private final ScmConfiguration configuration;
+ /** scm main configuration */
+ protected ScmConfiguration configuration;
}
diff --git a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java
index 9767f1d43e..8900342bda 100644
--- a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java
+++ b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java
@@ -49,6 +49,7 @@ import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.PermissionType;
import sonia.scm.repository.PermissionUtil;
import sonia.scm.repository.Repository;
+import sonia.scm.security.Role;
import sonia.scm.security.ScmSecurityException;
import sonia.scm.util.HttpUtil;
import sonia.scm.util.Util;
@@ -63,7 +64,6 @@ import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import sonia.scm.security.Role;
/**
* Abstract http filter to check repository permissions.
@@ -116,11 +116,11 @@ public abstract class PermissionFilter extends HttpFilter
//~--- methods --------------------------------------------------------------
/**
- * Checks the permission for the requested repository. If the user has enough
+ * Checks the permission for the requested repository. If the user has enough
* permission, then the filter chain is called.
*
*
- * @param request http request
+ * @param request http request
* @param response http response
* @param chain filter chain
*
@@ -162,7 +162,7 @@ public abstract class PermissionFilter extends HttpFilter
getUserName(subject));
}
- sendAccessDenied(response, subject);
+ sendAccessDenied(request, response, subject);
}
}
else
@@ -199,11 +199,43 @@ public abstract class PermissionFilter extends HttpFilter
subject.getPrincipal());
}
- sendAccessDenied(response, subject);
+ sendAccessDenied(request, response, subject);
}
}
+ /**
+ * Sends a "not enough privileges" error back to client.
+ *
+ *
+ * @param request http request
+ * @param response http response
+ *
+ * @throws IOException
+ */
+ protected void sendNotEnoughPrivilegesError(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException
+ {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ }
+
+ /**
+ * Sends an unauthorized error back to client.
+ *
+ *
+ * @param request http request
+ * @param response http response
+ *
+ * @throws IOException
+ */
+ protected void sendUnauthorizedError(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException
+ {
+ HttpUtil.sendUnauthorized(response, configuration.getRealmDescription());
+ }
+
/**
* Extracts the type of the repositroy from url.
*
@@ -230,22 +262,23 @@ public abstract class PermissionFilter extends HttpFilter
/**
* Send access denied to the servlet response.
*
- *
+ * @param request current http request object
* @param response current http response object
* @param subject user subject
*
* @throws IOException
*/
- private void sendAccessDenied(HttpServletResponse response, Subject subject)
+ private void sendAccessDenied(HttpServletRequest request,
+ HttpServletResponse response, Subject subject)
throws IOException
{
if (subject.hasRole(Role.USER))
{
- response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ sendNotEnoughPrivilegesError(request, response);
}
else
{
- HttpUtil.sendUnauthorized(response, configuration.getRealmDescription());
+ sendUnauthorizedError(request, response);
}
}
@@ -334,5 +367,5 @@ public abstract class PermissionFilter extends HttpFilter
//~--- fields ---------------------------------------------------------------
/** scm-manager global configuration */
- private ScmConfiguration configuration;
+ private final ScmConfiguration configuration;
}
diff --git a/scm-core/src/main/resources/sonia/scm/ClientMessages.properties b/scm-core/src/main/resources/sonia/scm/ClientMessages.properties
new file mode 100644
index 0000000000..9141761056
--- /dev/null
+++ b/scm-core/src/main/resources/sonia/scm/ClientMessages.properties
@@ -0,0 +1,31 @@
+# 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
+#
+
+failedAuthentication = Invalid username or password.
+notEnoughPrivileges = You do not have enough access privileges for this operation.
\ No newline at end of file
diff --git a/scm-core/src/test/java/sonia/scm/i18n/I18nMessagesTest.java b/scm-core/src/test/java/sonia/scm/i18n/I18nMessagesTest.java
new file mode 100644
index 0000000000..0760c4efb6
--- /dev/null
+++ b/scm-core/src/test/java/sonia/scm/i18n/I18nMessagesTest.java
@@ -0,0 +1,95 @@
+/**
+ * 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.i18n;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import org.junit.Test;
+
+import sonia.scm.repository.Changeset;
+
+import static org.junit.Assert.*;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.util.Locale;
+import java.util.MissingResourceException;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class I18nMessagesTest
+{
+
+ /**
+ * Method description
+ *
+ */
+ @Test
+ public void testI18n()
+ {
+ TestMessages msg = I18nMessages.get(TestMessages.class);
+
+ assertEquals("Normal Key", msg.normalKey);
+ assertEquals("Key with Annotation", msg.keyWithAnnotation);
+ assertNull(msg.someObject);
+ assertNotNull(msg.bundle);
+ assertEquals(Locale.ENGLISH, msg.locale);
+ }
+
+ /**
+ * Method description
+ *
+ */
+ @Test
+ public void testI18nOtherLanguage()
+ {
+ TestMessages msg = I18nMessages.get(TestMessages.class, Locale.GERMANY);
+
+ assertEquals("Normaler Schlüssel", msg.normalKey);
+ assertEquals("Schlüssel mit Annotation", msg.keyWithAnnotation);
+ assertNull(msg.someObject);
+ assertNotNull(msg.bundle);
+ assertEquals(Locale.GERMANY, msg.locale);
+ }
+
+ /**
+ * Method description
+ *
+ */
+ @Test(expected = MissingResourceException.class)
+ public void testMissingBundle()
+ {
+ Changeset msg = I18nMessages.get(Changeset.class);
+ }
+}
diff --git a/scm-core/src/test/java/sonia/scm/i18n/TestMessages.java b/scm-core/src/test/java/sonia/scm/i18n/TestMessages.java
new file mode 100644
index 0000000000..e1901eace9
--- /dev/null
+++ b/scm-core/src/test/java/sonia/scm/i18n/TestMessages.java
@@ -0,0 +1,60 @@
+/**
+ * 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.i18n;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.util.Locale;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class TestMessages
+{
+
+ /** Field description */
+ public Bundle bundle;
+
+ /** Field description */
+ @I18n("key_with_annotation")
+ public String keyWithAnnotation;
+
+ /** Field description */
+ public Locale locale;
+
+ /** Field description */
+ public String normalKey;
+
+ /** Field description */
+ public Integer someObject;
+}
diff --git a/scm-core/src/test/java/sonia/scm/io/DeepCopyTest.java b/scm-core/src/test/java/sonia/scm/io/DeepCopyTest.java
new file mode 100644
index 0000000000..f21c304d58
--- /dev/null
+++ b/scm-core/src/test/java/sonia/scm/io/DeepCopyTest.java
@@ -0,0 +1,328 @@
+/**
+ * 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.io;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.common.base.Objects;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class DeepCopyTest
+{
+
+ /**
+ * Method description
+ *
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testDeepCopy() throws IOException
+ {
+ Person orig = new Person("Tricia", "McMillan",
+ new Address("Magrathea", "Mainstreet 3"));
+ Person copy = DeepCopy.copy(orig);
+
+ assertNotSame(orig, copy);
+ assertEquals(orig, copy);
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @throws IOException
+ */
+ @Test(expected = IOException.class)
+ public void testDeepCopyNonSerializable() throws IOException
+ {
+ DeepCopy.copy(new NonSerializable());
+ }
+
+ //~--- inner classes --------------------------------------------------------
+
+ /**
+ * Class description
+ *
+ *
+ * @version Enter version here..., 14/03/08
+ * @author Enter your name here...
+ */
+ private static class Address implements Serializable
+ {
+
+ /** Field description */
+ private static final long serialVersionUID = 3200816222378286310L;
+
+ //~--- constructors -------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ */
+ public Address() {}
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param city
+ * @param street
+ */
+ public Address(String city, String street)
+ {
+ this.city = city;
+ this.street = street;
+ }
+
+ //~--- methods ------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param obj
+ *
+ * @return
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+
+ final Address other = (Address) obj;
+
+ return Objects.equal(city, other.city)
+ && Objects.equal(street, other.street);
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public int hashCode()
+ {
+ return Objects.hashCode(city, street);
+ }
+
+ //~--- get methods --------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getCity()
+ {
+ return city;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getStreet()
+ {
+ return street;
+ }
+
+ //~--- fields -------------------------------------------------------------
+
+ /** Field description */
+ private String city;
+
+ /** Field description */
+ private String street;
+ }
+
+
+ /**
+ * Class description
+ *
+ *
+ * @version Enter version here..., 14/03/08
+ * @author Enter your name here...
+ */
+ private static class NonSerializable {}
+
+
+ /**
+ * Class description
+ *
+ *
+ * @version Enter version here..., 14/03/08
+ * @author Enter your name here...
+ */
+ private static class Person implements Serializable
+ {
+
+ /** Field description */
+ private static final long serialVersionUID = -2098386757802626539L;
+
+ //~--- constructors -------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ */
+ public Person() {}
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param firstname
+ * @param lastname
+ * @param address
+ */
+ public Person(String firstname, String lastname, Address address)
+ {
+ this.firstname = firstname;
+ this.lastname = lastname;
+ this.address = address;
+ }
+
+ //~--- methods ------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param obj
+ *
+ * @return
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+
+ final Person other = (Person) obj;
+
+ return Objects.equal(firstname, other.firstname)
+ && Objects.equal(lastname, other.lastname)
+ && Objects.equal(address, other.address);
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public int hashCode()
+ {
+ return Objects.hashCode(firstname, lastname, address);
+ }
+
+ //~--- get methods --------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public Address getAddress()
+ {
+ return address;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getFirstname()
+ {
+ return firstname;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getLastname()
+ {
+ return lastname;
+ }
+
+ //~--- fields -------------------------------------------------------------
+
+ /** Field description */
+ private Address address;
+
+ /** Field description */
+ private String firstname;
+
+ /** Field description */
+ private String lastname;
+ }
+}
diff --git a/scm-core/src/test/java/sonia/scm/search/SearchUtilTest.java b/scm-core/src/test/java/sonia/scm/search/SearchUtilTest.java
index 8aebfa9dbd..0588729a45 100644
--- a/scm-core/src/test/java/sonia/scm/search/SearchUtilTest.java
+++ b/scm-core/src/test/java/sonia/scm/search/SearchUtilTest.java
@@ -177,6 +177,12 @@ public class SearchUtilTest
"testhansolo"));
assertFalse(SearchUtil.matchesAll(new SearchRequest("test\\hansolo"),
"test\\hnsolo"));
+ assertTrue(SearchUtil.matchesAll(new SearchRequest("{test,hansolo} tst"),
+ "{test,hansolo} tst"));
+ assertTrue(SearchUtil.matchesAll(new SearchRequest("(test,hansolo) tst"),
+ "(test,hansolo) tst"));
+ assertTrue(SearchUtil.matchesAll(new SearchRequest("[test,hansolo] tst"),
+ "[test,hansolo] tst"));
}
/**
diff --git a/scm-core/src/test/java/sonia/scm/util/HttpUtilTest.java b/scm-core/src/test/java/sonia/scm/util/HttpUtilTest.java
index 4f88616662..585bc0e005 100644
--- a/scm-core/src/test/java/sonia/scm/util/HttpUtilTest.java
+++ b/scm-core/src/test/java/sonia/scm/util/HttpUtilTest.java
@@ -184,6 +184,23 @@ public class HttpUtilTest
}
+ /**
+ * Method description
+ *
+ */
+ @Test
+ public void userAgentStartsWithTest()
+ {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+
+ when(request.getHeader(HttpUtil.HEADER_USERAGENT)).thenReturn(
+ "git/1.7.10.5997.gaa4aa");
+ assertTrue(HttpUtil.userAgentStartsWith(request, "git/"));
+ assertTrue(HttpUtil.userAgentStartsWith(request, "GIT/"));
+ assertFalse(HttpUtil.userAgentStartsWith(request, "git/a"));
+ assertFalse(HttpUtil.userAgentStartsWith(request, "sobbo/"));
+ }
+
//~--- get methods ----------------------------------------------------------
/**
diff --git a/scm-core/src/test/resources/sonia/scm/i18n/TestMessages.properties b/scm-core/src/test/resources/sonia/scm/i18n/TestMessages.properties
new file mode 100644
index 0000000000..06a80bcae0
--- /dev/null
+++ b/scm-core/src/test/resources/sonia/scm/i18n/TestMessages.properties
@@ -0,0 +1,30 @@
+# 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
+#
+key_with_annotation = Key with Annotation
+normalKey = Normal Key
\ No newline at end of file
diff --git a/scm-core/src/test/resources/sonia/scm/i18n/TestMessages_de_DE.properties b/scm-core/src/test/resources/sonia/scm/i18n/TestMessages_de_DE.properties
new file mode 100644
index 0000000000..c370bc25d8
--- /dev/null
+++ b/scm-core/src/test/resources/sonia/scm/i18n/TestMessages_de_DE.properties
@@ -0,0 +1,30 @@
+# 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
+#
+key_with_annotation = Schl\u00fcssel mit Annotation
+normalKey = Normaler Schl\u00fcssel
\ No newline at end of file
diff --git a/scm-dao-xml/src/main/java/sonia/scm/store/JAXBConfigurationEntryStore.java b/scm-dao-xml/src/main/java/sonia/scm/store/JAXBConfigurationEntryStore.java
index 3fafd26e6d..fea2c7220a 100644
--- a/scm-dao-xml/src/main/java/sonia/scm/store/JAXBConfigurationEntryStore.java
+++ b/scm-dao-xml/src/main/java/sonia/scm/store/JAXBConfigurationEntryStore.java
@@ -409,7 +409,7 @@ public class JAXBConfigurationEntryStore
{
//J-
writer = new IndentXMLStreamWriter(
- XMLOutputFactory.newFactory().createXMLStreamWriter(
+ XMLOutputFactory.newInstance().createXMLStreamWriter(
createWriter()
)
);
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java
index 6dd4996b47..8bd530d5e9 100644
--- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java
@@ -36,6 +36,7 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
@@ -59,6 +60,7 @@ import org.eclipse.jgit.util.FS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import sonia.scm.util.HttpUtil;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
@@ -66,9 +68,12 @@ import sonia.scm.util.Util;
import java.io.File;
import java.io.IOException;
+import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
+import javax.servlet.http.HttpServletRequest;
+
/**
*
* @author Sebastian Sdorra
@@ -109,6 +114,9 @@ public final class GitUtil
/** Field description */
private static final int TIMEOUT = 5;
+ /** Field description */
+ private static final String USERAGENT_GIT = "git/";
+
/** the logger for GitUtil */
private static final Logger logger = LoggerFactory.getLogger(GitUtil.class);
@@ -652,6 +660,19 @@ public final class GitUtil
return name;
}
+ /**
+ * Returns true if the request comes from a git client.
+ *
+ *
+ * @param request servlet request
+ *
+ * @return true if the client is git
+ */
+ public static boolean isGitClient(HttpServletRequest request)
+ {
+ return HttpUtil.userAgentStartsWith(request, USERAGENT_GIT);
+ }
+
/**
* Method description
*
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitBasicAuthenticationFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitBasicAuthenticationFilter.java
new file mode 100644
index 0000000000..5f71cf4e48
--- /dev/null
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitBasicAuthenticationFilter.java
@@ -0,0 +1,106 @@
+/**
+ * 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;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import org.eclipse.jgit.http.server.GitSmartHttpTools;
+
+import sonia.scm.ClientMessages;
+import sonia.scm.config.ScmConfiguration;
+import sonia.scm.repository.GitUtil;
+import sonia.scm.web.filter.AutoLoginModule;
+import sonia.scm.web.filter.BasicAuthenticationFilter;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.IOException;
+
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Singleton
+public class GitBasicAuthenticationFilter extends BasicAuthenticationFilter
+{
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param configuration
+ * @param autoLoginModules
+ */
+ @Inject
+ public GitBasicAuthenticationFilter(ScmConfiguration configuration,
+ Set autoLoginModules)
+ {
+ super(configuration, autoLoginModules);
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ * @param response
+ *
+ * @throws IOException
+ */
+ @Override
+ protected void sendFailedAuthenticationError(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException
+ {
+ System.out.println(ClientMessages.get(request).failedAuthentication());
+ if (GitUtil.isGitClient(request))
+ {
+ GitSmartHttpTools.sendError(request, response,
+ HttpServletResponse.SC_FORBIDDEN,
+ ClientMessages.get(request).failedAuthentication());
+ }
+ else
+ {
+ super.sendFailedAuthenticationError(request, response);
+ }
+ }
+}
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java
index c277c0cf7f..f682c355a6 100644
--- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java
@@ -38,13 +38,20 @@ package sonia.scm.web;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import org.eclipse.jgit.http.server.GitSmartHttpTools;
+
+import sonia.scm.ClientMessages;
+import sonia.scm.config.ScmConfiguration;
+import sonia.scm.repository.GitUtil;
import sonia.scm.repository.RepositoryProvider;
import sonia.scm.web.filter.ProviderPermissionFilter;
//~--- JDK imports ------------------------------------------------------------
+import java.io.IOException;
+
import javax.servlet.http.HttpServletRequest;
-import sonia.scm.config.ScmConfiguration;
+import javax.servlet.http.HttpServletResponse;
/**
*
@@ -71,19 +78,44 @@ public class GitPermissionFilter extends ProviderPermissionFilter
/**
* Constructs ...
*
- *
- *
- * @param securityContextProvider
+ * @param configuration
* @param repositoryProvider
*/
@Inject
- public GitPermissionFilter(
- ScmConfiguration configuration,
- RepositoryProvider repositoryProvider)
+ public GitPermissionFilter(ScmConfiguration configuration,
+ RepositoryProvider repositoryProvider)
{
super(configuration, repositoryProvider);
}
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ * @param response
+ *
+ * @throws IOException
+ */
+ @Override
+ protected void sendNotEnoughPrivilegesError(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException
+ {
+ if (GitUtil.isGitClient(request))
+ {
+ GitSmartHttpTools.sendError(request, response,
+ HttpServletResponse.SC_FORBIDDEN,
+ ClientMessages.get(request).notEnoughPrivileges());
+ }
+ else
+ {
+ super.sendNotEnoughPrivilegesError(request, response);
+ }
+ }
+
//~--- get methods ----------------------------------------------------------
/**
@@ -100,8 +132,8 @@ public class GitPermissionFilter extends ProviderPermissionFilter
String uri = request.getRequestURI();
return uri.endsWith(URI_RECEIVE_PACK)
- || (uri.endsWith(URI_REF_INFO)
- && PARAMETER_VALUE_RECEIVE.equals(
- request.getParameter(PARAMETER_SERVICE)));
+ || (uri.endsWith(URI_REF_INFO)
+ && PARAMETER_VALUE_RECEIVE.equals(
+ request.getParameter(PARAMETER_SERVICE)));
}
}
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java
index fd7300817b..fdb1ae52d9 100644
--- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java
@@ -40,7 +40,6 @@ import com.google.inject.servlet.ServletModule;
import org.eclipse.jgit.transport.ScmTransportProtocol;
import sonia.scm.plugin.ext.Extension;
-import sonia.scm.web.filter.BasicAuthenticationFilter;
/**
*
@@ -68,7 +67,7 @@ public class GitServletModule extends ServletModule
bind(ScmTransportProtocol.class);
// serlvelts and filters
- filter(PATTERN_GIT).through(BasicAuthenticationFilter.class);
+ filter(PATTERN_GIT).through(GitBasicAuthenticationFilter.class);
filter(PATTERN_GIT).through(GitPermissionFilter.class);
serve(PATTERN_GIT).with(ScmGitServlet.class);
}
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgHookManager.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgHookManager.java
index 304e5b4d32..5f3ab09734 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgHookManager.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgHookManager.java
@@ -37,8 +37,11 @@ package sonia.scm.repository;
import com.github.legman.Subscribe;
+import com.google.common.base.Objects;
import com.google.inject.Inject;
+import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
+import com.google.inject.ProvisionException;
import com.google.inject.Singleton;
import org.slf4j.Logger;
@@ -152,7 +155,7 @@ public class HgHookManager
if (url == null)
{
- HttpServletRequest request = httpServletRequestProvider.get();
+ HttpServletRequest request = getHttpServletRequest();
if (request != null)
{
@@ -160,10 +163,10 @@ public class HgHookManager
}
else
{
- logger.warn(
- "created hook url {} without request, in some cases this could cause problems",
- hookUrl);
url = createConfiguredUrl();
+ logger.warn(
+ "created url {} without request, in some cases this could cause problems",
+ url);
}
}
@@ -269,8 +272,14 @@ public class HgHookManager
*/
private String createConfiguredUrl()
{
+ //J-
return HttpUtil.getUriWithoutEndSeperator(
- configuration.getBaseUrl()).concat("/hook/hg/");
+ Objects.firstNonNull(
+ configuration.getBaseUrl(),
+ "http://localhost:8080/scm"
+ )
+ ).concat("/hook/hg/");
+ //J+
}
/**
@@ -309,6 +318,32 @@ public class HgHookManager
//~--- get methods ----------------------------------------------------------
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ private HttpServletRequest getHttpServletRequest()
+ {
+ HttpServletRequest request = null;
+
+ try
+ {
+ request = httpServletRequestProvider.get();
+ }
+ catch (ProvisionException ex)
+ {
+ logger.debug("http servlet request is not available");
+ }
+ catch (OutOfScopeException ex)
+ {
+ logger.debug("http servlet request is not available");
+ }
+
+ return request;
+ }
+
/**
* Method description
*
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgBasicAuthenticationFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgBasicAuthenticationFilter.java
new file mode 100644
index 0000000000..afbef65557
--- /dev/null
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgBasicAuthenticationFilter.java
@@ -0,0 +1,99 @@
+/**
+ * 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;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import sonia.scm.config.ScmConfiguration;
+import sonia.scm.web.filter.AutoLoginModule;
+import sonia.scm.web.filter.BasicAuthenticationFilter;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.IOException;
+
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Singleton
+public class HgBasicAuthenticationFilter extends BasicAuthenticationFilter
+{
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param configuration
+ * @param autoLoginModules
+ */
+ @Inject
+ public HgBasicAuthenticationFilter(ScmConfiguration configuration,
+ Set autoLoginModules)
+ {
+ super(configuration, autoLoginModules);
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ * @param response
+ *
+ * @throws IOException
+ */
+ @Override
+ protected void sendFailedAuthenticationError(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException
+ {
+ if (HgUtil.isHgClient(request))
+ {
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+ else
+ {
+ super.sendFailedAuthenticationError(request, response);
+ }
+ }
+}
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java
index 73d20530ea..0a9d3e43b9 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java
@@ -57,9 +57,6 @@ public class HgPermissionFilter extends ProviderPermissionFilter
/**
* Constructs ...
*
- *
- * @param securityContextProvider
- *
* @param configuration
* @param repositoryProvider
*/
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java
index 792bafe80b..5bf080860a 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java
@@ -75,7 +75,7 @@ public class HgServletModule extends ServletModule
serve(MAPPING_HOOK).with(HgHookCallbackServlet.class);
// register hg cgi servlet
- filter(MAPPING_HG).through(BasicAuthenticationFilter.class);
+ filter(MAPPING_HG).through(HgBasicAuthenticationFilter.class);
filter(MAPPING_HG).through(HgPermissionFilter.class);
serve(MAPPING_HG).with(HgCGIServlet.class);
}
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java
index 0d7150205f..ec35762de7 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java
@@ -50,6 +50,7 @@ import sonia.scm.repository.HgHookManager;
import sonia.scm.repository.HgPythonScript;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.spi.javahg.HgFileviewExtension;
+import sonia.scm.util.HttpUtil;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
@@ -58,6 +59,8 @@ import java.io.File;
import java.nio.charset.Charset;
+import javax.servlet.http.HttpServletRequest;
+
/**
*
* @author Sebastian Sdorra
@@ -68,6 +71,9 @@ public final class HgUtil
/** Field description */
public static final String REVISION_TIP = "tip";
+ /** Field description */
+ private static final String USERAGENT_HG = "mercurial/";
+
/**
* the logger for HgUtil
*/
@@ -180,4 +186,17 @@ public final class HgUtil
? REVISION_TIP
: revision;
}
+
+ /**
+ * Returns true if the request comes from a mercurial client.
+ *
+ *
+ * @param request servlet request
+ *
+ * @return true if the client is mercurial
+ */
+ public static boolean isHgClient(HttpServletRequest request)
+ {
+ return HttpUtil.userAgentStartsWith(request, USERAGENT_HG);
+ }
}
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/ScmSvnErrorCode.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/ScmSvnErrorCode.java
new file mode 100644
index 0000000000..27d8523517
--- /dev/null
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/ScmSvnErrorCode.java
@@ -0,0 +1,77 @@
+/**
+ * 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.repository;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import org.tmatesoft.svn.core.SVNErrorCode;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public final class ScmSvnErrorCode extends SVNErrorCode
+{
+
+ /** Field description */
+ private static final long serialVersionUID = -6864996390796610410L;
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param category
+ * @param index
+ * @param description
+ */
+ protected ScmSvnErrorCode(int category, int index, String description)
+ {
+ super(category, index, description);
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param description
+ *
+ * @return
+ */
+ public static ScmSvnErrorCode authzNotEnoughPrivileges(String description)
+ {
+ return new ScmSvnErrorCode(AUTHZ_CATEGORY, 4, description);
+ }
+}
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java
index abe5689712..6cc5eb5da9 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java
@@ -37,23 +37,36 @@ package sonia.scm.repository;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
+import com.google.common.io.Closeables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;
+import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
+import org.tmatesoft.svn.core.internal.server.dav.DAVXMLUtil;
+import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
+import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.admin.SVNChangeEntry;
+import sonia.scm.util.HttpUtil;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
+import java.io.IOException;
+import java.io.PrintWriter;
+
import java.util.List;
import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
/**
*
* @author Sebastian Sdorra
@@ -61,6 +74,9 @@ import java.util.Map;
public final class SvnUtil
{
+ /** Field description */
+ public static final String XML_CONTENT_TYPE = "text/xml; charset=\"utf-8\"";
+
/** Field description */
private static final String ID_TRANSACTION_PREFIX = "-1:";
@@ -70,6 +86,9 @@ public final class SvnUtil
*/
private static final char TYPE_UPDATED = 'U';
+ /** Field description */
+ private static final String USERAGENT_SVN = "svn/";
+
/**
* the logger for SvnUtil
*/
@@ -232,6 +251,39 @@ public final class SvnUtil
return changesets;
}
+ /**
+ * Method description
+ *
+ * @param errorCode
+ *
+ * @return
+ */
+ public static String createErrorBody(SVNErrorCode errorCode)
+ {
+ StringBuffer xmlBuffer = new StringBuffer();
+
+ SVNXMLUtil.addXMLHeader(xmlBuffer);
+
+ List namespaces = Lists.newArrayList(DAVElement.DAV_NAMESPACE,
+ DAVElement.SVN_APACHE_PROPERTY_NAMESPACE);
+
+ SVNXMLUtil.openNamespaceDeclarationTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX,
+ DAVXMLUtil.SVN_DAV_ERROR_TAG, namespaces, SVNXMLUtil.PREFIX_MAP,
+ xmlBuffer);
+
+ SVNXMLUtil.openXMLTag(SVNXMLUtil.SVN_APACHE_PROPERTY_PREFIX,
+ "human-readable", SVNXMLUtil.XML_STYLE_NORMAL, "errcode",
+ String.valueOf(errorCode.getCode()), xmlBuffer);
+ xmlBuffer.append(
+ SVNEncodingUtil.xmlEncodeCDATA(errorCode.getDescription()));
+ SVNXMLUtil.closeXMLTag(SVNXMLUtil.SVN_APACHE_PROPERTY_PREFIX,
+ "human-readable", xmlBuffer);
+ SVNXMLUtil.closeXMLTag(SVNXMLUtil.DAV_NAMESPACE_PREFIX,
+ DAVXMLUtil.SVN_DAV_ERROR_TAG, xmlBuffer);
+
+ return xmlBuffer.toString();
+ }
+
/**
* Method description
*
@@ -266,6 +318,39 @@ public final class SvnUtil
}
}
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ * @param response
+ * @param statusCode
+ * @param errorCode
+ *
+ * @throws IOException
+ */
+ public static void sendError(HttpServletRequest request,
+ HttpServletResponse response, int statusCode, SVNErrorCode errorCode)
+ throws IOException
+ {
+ HttpUtil.drainBody(request);
+
+ response.setStatus(statusCode);
+ response.setContentType(XML_CONTENT_TYPE);
+
+ PrintWriter writer = null;
+
+ try
+ {
+ writer = response.getWriter();
+ writer.println(createErrorBody(errorCode));
+ }
+ finally
+ {
+ Closeables.close(writer, true);
+ }
+ }
+
//~--- get methods ----------------------------------------------------------
/**
@@ -311,6 +396,19 @@ public final class SvnUtil
return id.substring(ID_TRANSACTION_PREFIX.length());
}
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ *
+ * @return
+ */
+ public static boolean isSvnClient(HttpServletRequest request)
+ {
+ return HttpUtil.userAgentStartsWith(request, USERAGENT_SVN);
+ }
+
/**
* Method description
*
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnBasicAuthenticationFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnBasicAuthenticationFilter.java
new file mode 100644
index 0000000000..b94b6b5d56
--- /dev/null
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnBasicAuthenticationFilter.java
@@ -0,0 +1,102 @@
+/**
+ * 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;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import sonia.scm.config.ScmConfiguration;
+import sonia.scm.repository.SvnUtil;
+import sonia.scm.util.HttpUtil;
+import sonia.scm.web.filter.AutoLoginModule;
+import sonia.scm.web.filter.BasicAuthenticationFilter;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.IOException;
+
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+@Singleton
+public class SvnBasicAuthenticationFilter extends BasicAuthenticationFilter
+{
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param configuration
+ * @param autoLoginModules
+ */
+ @Inject
+ public SvnBasicAuthenticationFilter(ScmConfiguration configuration,
+ Set autoLoginModules)
+ {
+ super(configuration, autoLoginModules);
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Sends unauthorized instead of forbidden for svn clients, because the
+ * svn client prompts again for authentication.
+ *
+ *
+ * @param request http request
+ * @param response http response
+ *
+ * @throws IOException
+ */
+ @Override
+ protected void sendFailedAuthenticationError(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException
+ {
+ if (SvnUtil.isSvnClient(request))
+ {
+ HttpUtil.sendUnauthorized(response, configuration.getRealmDescription());
+ }
+ else
+ {
+ super.sendFailedAuthenticationError(request, response);
+ }
+ }
+}
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java
index 164ccfd173..bcaf854118 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java
@@ -39,15 +39,21 @@ import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import sonia.scm.ClientMessages;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.RepositoryProvider;
+import sonia.scm.repository.ScmSvnErrorCode;
+import sonia.scm.repository.SvnUtil;
import sonia.scm.web.filter.ProviderPermissionFilter;
//~--- JDK imports ------------------------------------------------------------
+import java.io.IOException;
+
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
/**
*
@@ -58,22 +64,16 @@ public class SvnPermissionFilter extends ProviderPermissionFilter
{
/** Field description */
- private static Set WRITEMETHOD_SET = ImmutableSet.of("MKACTIVITY",
- "PROPPATCH", "PUT",
- "CHECKOUT", "MKCOL", "MOVE",
- "COPY", "DELETE", "LOCK",
- "UNLOCK", "MERGE");
+ private static final Set WRITEMETHOD_SET =
+ ImmutableSet.of("MKACTIVITY", "PROPPATCH", "PUT", "CHECKOUT", "MKCOL",
+ "MOVE", "COPY", "DELETE", "LOCK", "UNLOCK", "MERGE");
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
- *
- *
- *
* @param configuration
- * @param securityContextProvider
* @param repository
*/
@Inject
@@ -83,6 +83,41 @@ public class SvnPermissionFilter extends ProviderPermissionFilter
super(configuration, repository);
}
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param request
+ * @param response
+ *
+ * @throws IOException
+ */
+ @Override
+ protected void sendNotEnoughPrivilegesError(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException
+ {
+ if (SvnUtil.isSvnClient(request))
+ {
+ //J-
+ SvnUtil.sendError(
+ request,
+ response,
+ HttpServletResponse.SC_FORBIDDEN,
+ ScmSvnErrorCode.authzNotEnoughPrivileges(
+ ClientMessages.get(request).notEnoughPrivileges()
+ )
+ );
+ //J+
+ }
+ else
+ {
+ super.sendNotEnoughPrivilegesError(request, response);
+ }
+ }
+
//~--- get methods ----------------------------------------------------------
/**
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java
index 689af8851b..9eda6fe7dd 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java
@@ -69,7 +69,7 @@ public class SvnServletModule extends ServletModule
protected void configureServlets()
{
filter(PATTERN_SVN).through(SvnGZipFilter.class);
- filter(PATTERN_SVN).through(BasicAuthenticationFilter.class);
+ filter(PATTERN_SVN).through(SvnBasicAuthenticationFilter.class);
filter(PATTERN_SVN).through(SvnPermissionFilter.class);
Map parameters = new HashMap();
diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml
index 29c5b00da1..29a836a0eb 100644
--- a/scm-webapp/pom.xml
+++ b/scm-webapp/pom.xml
@@ -164,13 +164,7 @@
commons-beanutils
commons-beanutils
- 1.8.3
-
-
- commons-logging
- commons-logging
-
-
+ 1.9.1
@@ -179,6 +173,17 @@
3.2.1
+
+
+
+ commons-codec
+ commons-codec
+ 1.9
+
+
asm
asm
@@ -300,12 +305,6 @@
selenium-java
${selenium.version}
test
-
-
- commons-logging
- commons-logging
-
-
@@ -327,12 +326,22 @@
jersey-apache-client
${jersey.version}
test
-
-
- commons-logging
- commons-logging
-
-
+
+
+
+
+
+ commons-logging
+ commons-logging
+ 1.1.3
+ provided
+
+
+
+ log4j
+ log4j
+ 1.2.17
+ provided
@@ -502,20 +511,6 @@
-
-
- cluster
-
-
-
-
- sonia.scm
- scm-dao-orientdb
- 2.0.0-SNAPSHOT
-
-
-
-
release
diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyFilter.java b/scm-webapp/src/main/java/sonia/scm/plugin/AbstractDependencyFilter.java
similarity index 73%
rename from scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyFilter.java
rename to scm-webapp/src/main/java/sonia/scm/plugin/AbstractDependencyFilter.java
index 1d89ddec7a..d448358b64 100644
--- a/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyFilter.java
+++ b/scm-webapp/src/main/java/sonia/scm/plugin/AbstractDependencyFilter.java
@@ -35,42 +35,47 @@ package sonia.scm.plugin;
//~--- non-JDK imports --------------------------------------------------------
+import com.google.common.base.Throwables;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.graph.DependencyFilter;
import org.sonatype.aether.graph.DependencyNode;
-import sonia.scm.util.Util;
-
//~--- JDK imports ------------------------------------------------------------
-import java.util.HashSet;
+import java.io.IOException;
+
import java.util.List;
-import java.util.Scanner;
import java.util.Set;
/**
*
* @author Sebastian Sdorra
*/
-public class AetherDependencyFilter implements DependencyFilter
+public abstract class AbstractDependencyFilter implements DependencyFilter
{
- /** Field description */
- public static final String EXCLUDE_LIST = "/config/dependencies.list";
-
- //~--- constructors ---------------------------------------------------------
-
/**
- * Constructs ...
- *
+ * the logger for AbstractDependencyFilter
*/
- public AetherDependencyFilter()
- {
- loadExcludes();
- }
+ private static final Logger logger =
+ LoggerFactory.getLogger(AbstractDependencyFilter.class);
//~--- methods --------------------------------------------------------------
+ /**
+ * Method description
+ *
+ *
+ * @return
+ *
+ * @throws IOException
+ */
+ protected abstract Set loadExcludeSet() throws IOException;
+
/**
* Method description
*
@@ -91,63 +96,45 @@ public class AetherDependencyFilter implements DependencyFilter
if (artifact != null)
{
- result = !exludeSet.contains(getId(artifact));
+ String id = getId(artifact);
+
+ result = !getExludeSet().contains(id);
+
+ if (!result && logger.isDebugEnabled())
+ {
+ logger.debug("exlcude dependency {} because it is blacklisted", id);
+ }
}
}
return result;
}
- /**
- * Method description
- *
- */
- private void loadExcludes()
- {
- Scanner scanner = null;
-
- try
- {
- scanner = new Scanner(
- AetherDependencyFilter.class.getResourceAsStream(EXCLUDE_LIST));
-
- while (scanner.hasNextLine())
- {
- parseLine(scanner.nextLine());
- }
- }
- finally
- {
- if (scanner != null)
- {
- scanner.close();
- }
- }
- }
-
- /**
- * Method description
- *
- *
- * @param line
- */
- private void parseLine(String line)
- {
- line = line.trim();
-
- if (Util.isNotEmpty(line))
- {
- String[] parts = line.split(":");
-
- if (parts.length >= 2)
- {
- exludeSet.add(parts[0].concat(":").concat(parts[1]));
- }
- }
- }
-
//~--- get methods ----------------------------------------------------------
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ private Set getExludeSet()
+ {
+ if (exludeSet == null)
+ {
+ try
+ {
+ exludeSet = loadExcludeSet();
+ }
+ catch (IOException ex)
+ {
+ throw Throwables.propagate(ex);
+ }
+ }
+
+ return exludeSet;
+ }
+
/**
* Method description
*
@@ -164,5 +151,5 @@ public class AetherDependencyFilter implements DependencyFilter
//~--- fields ---------------------------------------------------------------
/** Field description */
- private Set exludeSet = new HashSet();
+ private Set exludeSet;
}
diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/Aether.java b/scm-webapp/src/main/java/sonia/scm/plugin/Aether.java
index 80f99cd918..6a27d5758f 100644
--- a/scm-webapp/src/main/java/sonia/scm/plugin/Aether.java
+++ b/scm-webapp/src/main/java/sonia/scm/plugin/Aether.java
@@ -57,6 +57,7 @@ import org.sonatype.aether.resolution.DependencyRequest;
import org.sonatype.aether.resolution.DependencyResolutionException;
import org.sonatype.aether.util.artifact.DefaultArtifact;
import org.sonatype.aether.util.artifact.JavaScopes;
+import org.sonatype.aether.util.filter.AndDependencyFilter;
import org.sonatype.aether.util.filter.DependencyFilterUtils;
import org.sonatype.aether.util.graph.transformer
.ChainedDependencyGraphTransformer;
@@ -77,7 +78,11 @@ public final class Aether
{
/** Field description */
- private static final DependencyFilter FILTER = new AetherDependencyFilter();
+ private static final DependencyFilter FILTER =
+ new AndDependencyFilter(
+ new CoreDependencyFilter(),
+ new BlacklistDependencyFilter()
+ );
/**
* the logger for Aether
@@ -167,7 +172,6 @@ public final class Aether
*
*
* @param system
- * @param repositoryManager
* @param localRepository
* @param configuration
*
diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyResolver.java b/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyResolver.java
index 1e42d84637..67bf4e8a40 100644
--- a/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyResolver.java
+++ b/scm-webapp/src/main/java/sonia/scm/plugin/AetherDependencyResolver.java
@@ -30,6 +30,7 @@
*/
+
package sonia.scm.plugin;
//~--- non-JDK imports --------------------------------------------------------
@@ -116,32 +117,17 @@ public class AetherDependencyResolver
*
*
* @param dependency
+ * @param dependencies
*
* @throws DependencyCollectionException
* @throws DependencyResolutionException
*/
- public void resolveLocalDependency(Dependency dependency)
+ public void resolveDependencies(Dependency dependency,
+ List dependencies)
throws DependencyCollectionException, DependencyResolutionException
{
- CollectRequest request = new CollectRequest();
-
- request.setRoot(dependency);
- resolveDependency(request);
- }
-
- /**
- * Method description
- *
- *
- * @param dependency
- *
- * @throws DependencyCollectionException
- * @throws DependencyResolutionException
- */
- public void resolveRemoteDependency(Dependency dependency)
- throws DependencyCollectionException, DependencyResolutionException
- {
- resolveDependency(new CollectRequest(dependency, remoteRepositories));
+ resolveDependency(new CollectRequest(dependency, dependencies,
+ remoteRepositories));
}
/**
diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java b/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java
index f35a6b4976..7de5397a23 100644
--- a/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java
+++ b/scm-webapp/src/main/java/sonia/scm/plugin/AetherPluginHandler.java
@@ -199,12 +199,7 @@ public class AetherPluginHandler
new AetherDependencyResolver(configuration, repositorySystem,
localRepository, remoteRepositories);
- resolver.resolveRemoteDependency(dependency);
-
- for (Dependency localDependency : localDependencies)
- {
- resolver.resolveLocalDependency(localDependency);
- }
+ resolver.resolveDependencies(dependency, localDependencies);
if (classpath == null)
{
diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/BlacklistDependencyFilter.java b/scm-webapp/src/main/java/sonia/scm/plugin/BlacklistDependencyFilter.java
new file mode 100644
index 0000000000..b01da86a32
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/plugin/BlacklistDependencyFilter.java
@@ -0,0 +1,65 @@
+/**
+ * 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.plugin;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.IOException;
+
+import java.util.Set;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class BlacklistDependencyFilter extends AbstractDependencyFilter
+{
+
+ /** Field description */
+ private static final String BLACKLIST = "/config/blacklist.list";
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ *
+ * @throws IOException
+ */
+ @Override
+ protected Set loadExcludeSet() throws IOException
+ {
+ return DependencyFilters.loadDependencySet(BLACKLIST);
+ }
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/CoreDependencyFilter.java b/scm-webapp/src/main/java/sonia/scm/plugin/CoreDependencyFilter.java
new file mode 100644
index 0000000000..528cc19ef5
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/plugin/CoreDependencyFilter.java
@@ -0,0 +1,65 @@
+/**
+ * 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.plugin;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.IOException;
+
+import java.util.Set;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class CoreDependencyFilter extends AbstractDependencyFilter
+{
+
+ /** Field description */
+ private static final String CORE_DEPENDENCIES = "/config/dependencies.list";
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ *
+ * @throws IOException
+ */
+ @Override
+ protected Set loadExcludeSet() throws IOException
+ {
+ return DependencyFilters.loadDependencySet(CORE_DEPENDENCIES);
+ }
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/DependencyFilters.java b/scm-webapp/src/main/java/sonia/scm/plugin/DependencyFilters.java
new file mode 100644
index 0000000000..a2088f07b2
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/plugin/DependencyFilters.java
@@ -0,0 +1,110 @@
+/**
+ * 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.plugin;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.io.Resources;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.IOException;
+
+import java.net.URL;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public final class DependencyFilters
+{
+
+ /**
+ * Method description
+ *
+ *
+ * @param path
+ *
+ * @return
+ *
+ * @throws IOException
+ */
+ public static Set loadDependencySet(String path) throws IOException
+ {
+ URL url = Resources.getResource(DependencyFilters.class, path);
+
+ if (url == null)
+ {
+ throw new IllegalArgumentException(
+ "could not find dependency set at ".concat(path));
+ }
+
+ Builder builder = ImmutableSet.builder();
+ List lines = Resources.readLines(url, Charsets.UTF_8);
+
+ for (String line : lines)
+ {
+ parseAndAppendLine(builder, line);
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param builder
+ * @param line
+ */
+ private static void parseAndAppendLine(Builder builder, String line)
+ {
+ line = line.trim();
+
+ if (!Strings.isNullOrEmpty(line))
+ {
+ String[] parts = line.split(":");
+
+ if (parts.length >= 2)
+ {
+ builder.add(parts[0].concat(":").concat(parts[1]));
+ }
+ }
+ }
+}
diff --git a/scm-webapp/src/main/resources/config/blacklist.list b/scm-webapp/src/main/resources/config/blacklist.list
new file mode 100644
index 0000000000..e6fb1b0be7
--- /dev/null
+++ b/scm-webapp/src/main/resources/config/blacklist.list
@@ -0,0 +1,10 @@
+
+The following dependencies are blacklisted
+ commons-logging:commons-logging
+ log4j:log4j
+ junit:junit
+ org.mockito:mockito-core
+ org.mockito:mockito-all
+ org.mockito:mockito-junit
+ org.testng:testng
+ org.powermock:powermock
\ No newline at end of file
diff --git a/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js b/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js
index 35ba82adb2..b1c0a5372f 100644
--- a/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js
+++ b/scm-webapp/src/main/webapp/resources/js/action/sonia.action.changepasswordwindow.js
@@ -64,9 +64,7 @@ Sonia.action.ChangePasswordWindow = Ext.extend(Ext.Window,{
name: 'old-password',
fieldLabel: this.oldPasswordText,
inputType: 'password',
- allowBlank: false,
- minLength: 6,
- maxLength: 32
+ allowBlank: false
},{
id: 'new-password',
name: 'new-password',
diff --git a/scm-webapp/src/main/webapp/resources/js/override/ext.form.vtypes.js b/scm-webapp/src/main/webapp/resources/js/override/ext.form.vtypes.js
index df17eeaee7..91d5307577 100644
--- a/scm-webapp/src/main/webapp/resources/js/override/ext.form.vtypes.js
+++ b/scm-webapp/src/main/webapp/resources/js/override/ext.form.vtypes.js
@@ -75,7 +75,7 @@ Ext.apply(Ext.form.VTypes, {
// username validator
username: function(val){
- return name(val);
+ return this.name(val);
},
usernameText: 'The username is invalid.'