merge with branch 1.x

This commit is contained in:
Sebastian Sdorra
2014-03-17 10:49:52 +01:00
51 changed files with 2711 additions and 210 deletions

16
pom.xml
View File

@@ -169,6 +169,14 @@
<version>1.0</version>
</signature>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
@@ -438,7 +446,7 @@
<logback.version>1.1.1</logback.version>
<servlet.version>2.5</servlet.version>
<guice.version>3.0</guice.version>
<jersey.version>1.18</jersey.version>
<jersey.version>1.18.1</jersey.version>
<freemarker.version>2.3.20</freemarker.version>
<jetty.version>7.6.14.v20131031</jetty.version>
@@ -446,11 +454,11 @@
<legman.version>1.2.0</legman.version>
<!-- security libraries -->
<shiro.version>1.2.2</shiro.version>
<shiro.version>1.2.3</shiro.version>
<!-- repostitory libraries -->
<jgit.version>3.2.0.201312181205-r</jgit.version>
<svnkit.version>1.8.3-scm1</svnkit.version>
<jgit.version>3.3.0.201403021825-r</jgit.version>
<svnkit.version>1.8.4-scm2</svnkit.version>
<!-- util libraries -->
<guava.version>16.0</guava.version>

View File

@@ -41,7 +41,7 @@
<dependency>
<groupId>args4j</groupId>
<artifactId>args4j</artifactId>
<version>2.0.25</version>
<version>2.0.26</version>
</dependency>
<dependency>

View File

@@ -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
)

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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);
}
}

View File

@@ -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<CacheKey, Object> 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 <T> type of message class
*
* @return instance of message class
*/
public static <T> T get(Class<T> 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 <T> type of message class
*
* @return
*/
public static <T> T get(Class<T> 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 <T> type of the message class
*
* @return instance of message class
*/
public synchronized static <T> T get(Class<T> 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 <T>
*
* @return
*/
private static <T> T createInstance(Class<T> 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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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);
@@ -197,9 +206,9 @@ 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))
{
@@ -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.
*

View File

@@ -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;
}

View File

@@ -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.
@@ -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;
}

View File

@@ -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.

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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"));
}
/**

View File

@@ -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 ----------------------------------------------------------
/**

View File

@@ -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

View File

@@ -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

View File

@@ -409,7 +409,7 @@ public class JAXBConfigurationEntryStore<V>
{
//J-
writer = new IndentXMLStreamWriter(
XMLOutputFactory.newFactory().createXMLStreamWriter(
XMLOutputFactory.newInstance().createXMLStreamWriter(
createWriter()
)
);

View File

@@ -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
*

View File

@@ -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<AutoLoginModule> 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);
}
}
}

View File

@@ -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)));
}
}

View File

@@ -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);
}

View File

@@ -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
*

View File

@@ -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<AutoLoginModule> 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);
}
}
}

View File

@@ -57,9 +57,6 @@ public class HgPermissionFilter extends ProviderPermissionFilter
/**
* Constructs ...
*
*
* @param securityContextProvider
*
* @param configuration
* @param repositoryProvider
*/

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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<String> 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
*

View File

@@ -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<AutoLoginModule> 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);
}
}
}

View File

@@ -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<String> WRITEMETHOD_SET = ImmutableSet.of("MKACTIVITY",
"PROPPATCH", "PUT",
"CHECKOUT", "MKCOL", "MOVE",
"COPY", "DELETE", "LOCK",
"UNLOCK", "MERGE");
private static final Set<String> 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 ----------------------------------------------------------
/**

View File

@@ -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<String, String> parameters = new HashMap<String, String>();

View File

@@ -164,13 +164,7 @@
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
<version>1.9.1</version>
</dependency>
<dependency>
@@ -179,6 +173,17 @@
<version>3.2.1</version>
</dependency>
<!--
fix installation of httpasswd-plugin
https://groups.google.com/d/topic/scmmanager/eN7UtG8TwW8/discussion
-->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
@@ -300,12 +305,6 @@
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
@@ -327,12 +326,22 @@
<artifactId>jersey-apache-client</artifactId>
<version>${jersey.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- global excludes -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<scope>provided</scope>
</dependency>
</dependencies>
@@ -503,20 +512,6 @@
<profiles>
<profile>
<id>cluster</id>
<dependencies>
<dependency>
<groupId>sonia.scm</groupId>
<artifactId>scm-dao-orientdb</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>release</id>

View File

@@ -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<String> 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<String> 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<String> exludeSet = new HashSet<String>();
private Set<String> exludeSet;
}

View File

@@ -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
*

View File

@@ -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<Dependency> 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));
}
/**

View File

@@ -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)
{

View File

@@ -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<String> loadExcludeSet() throws IOException
{
return DependencyFilters.loadDependencySet(BLACKLIST);
}
}

View File

@@ -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<String> loadExcludeSet() throws IOException
{
return DependencyFilters.loadDependencySet(CORE_DEPENDENCIES);
}
}

View File

@@ -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<String> 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<String> builder = ImmutableSet.builder();
List<String> 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<String> 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]));
}
}
}
}

View File

@@ -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

View File

@@ -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',

View File

@@ -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.'