mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-04-01 18:00:12 +02:00
move sources from scm-web-api and scm-cli to scm-core
This commit is contained in:
55
scm-core/src/main/java/sonia/scm/cli/Argument.java
Normal file
55
scm-core/src/main/java/sonia/scm/cli/Argument.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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.cli;
|
||||
|
||||
//~--- 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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Documented
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Argument
|
||||
{
|
||||
String value();
|
||||
String longName() default "";
|
||||
String description() default "";
|
||||
boolean required() default false;
|
||||
}
|
||||
80
scm-core/src/main/java/sonia/scm/cli/CliException.java
Normal file
80
scm-core/src/main/java/sonia/scm/cli/CliException.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 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.cli;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class CliException extends Exception
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*/
|
||||
public CliException() {}
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param string
|
||||
*/
|
||||
public CliException(String string)
|
||||
{
|
||||
super(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param thrwbl
|
||||
*/
|
||||
public CliException(Throwable thrwbl)
|
||||
{
|
||||
super(thrwbl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param string
|
||||
* @param thrwbl
|
||||
*/
|
||||
public CliException(String string, Throwable thrwbl)
|
||||
{
|
||||
super(string, thrwbl);
|
||||
}
|
||||
}
|
||||
54
scm-core/src/main/java/sonia/scm/cli/CliHelpBuilder.java
Normal file
54
scm-core/src/main/java/sonia/scm/cli/CliHelpBuilder.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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.cli;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public interface CliHelpBuilder
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param arguments
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String createHelp(List<Argument> arguments);
|
||||
}
|
||||
194
scm-core/src/main/java/sonia/scm/cli/CliParser.java
Normal file
194
scm-core/src/main/java/sonia/scm/cli/CliParser.java
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* 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.cli;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class CliParser
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param helpBuilder
|
||||
* @param clazz
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String createHelp(CliHelpBuilder helpBuilder, Class clazz)
|
||||
{
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
List<Argument> arguments = new ArrayList<Argument>();
|
||||
|
||||
for (Field field : fields)
|
||||
{
|
||||
Argument argument = field.getAnnotation(Argument.class);
|
||||
|
||||
if (argument != null)
|
||||
{
|
||||
arguments.add(argument);
|
||||
}
|
||||
}
|
||||
|
||||
return helpBuilder.createHelp(arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param helpBuilder
|
||||
* @param object
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String createHelp(CliHelpBuilder helpBuilder, Object object)
|
||||
{
|
||||
return createHelp(helpBuilder, object.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param object
|
||||
* @param arguments
|
||||
*
|
||||
* @throws CliException
|
||||
*/
|
||||
public void parse(Object object, String[] arguments) throws CliException
|
||||
{
|
||||
Field[] fields = object.getClass().getDeclaredFields();
|
||||
int length = arguments.length;
|
||||
|
||||
for (Field field : fields)
|
||||
{
|
||||
Argument argument = field.getAnnotation(Argument.class);
|
||||
|
||||
if (argument != null)
|
||||
{
|
||||
String name = "-" + argument.value();
|
||||
String longName = "--" + argument.longName();
|
||||
boolean found = false;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (arguments[i].equals(name)
|
||||
|| (!longName.equals("--") && arguments[i].startsWith(longName)))
|
||||
{
|
||||
found = true;
|
||||
|
||||
if (field.getType().isAssignableFrom(Boolean.class))
|
||||
{
|
||||
setArgument(object, field, Boolean.TRUE);
|
||||
}
|
||||
else if (arguments[i].equals(name) && (i + 1 < length))
|
||||
{
|
||||
setArgument(object, field,
|
||||
ConvertUtil.convertString(field.getType(),
|
||||
arguments[i + 1]));
|
||||
}
|
||||
else if (arguments[i].startsWith(longName + "="))
|
||||
{
|
||||
String value = arguments[i].substring(longName.length() + 1);
|
||||
|
||||
if ((value != null) && (value.length() > 0))
|
||||
{
|
||||
setArgument(object, field,
|
||||
ConvertUtil.convertString(field.getType(), value));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new CliException("missing parameter for " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && argument.required())
|
||||
{
|
||||
throw new CliRequiredException(name + " is required");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//~--- set methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param object
|
||||
* @param field
|
||||
* @param value
|
||||
*
|
||||
* @throws CliException
|
||||
*/
|
||||
private void setArgument(Object object, Field field, Object value)
|
||||
throws CliException
|
||||
{
|
||||
try
|
||||
{
|
||||
boolean modifyAccess = false;
|
||||
|
||||
if (!field.isAccessible())
|
||||
{
|
||||
field.setAccessible(true);
|
||||
modifyAccess = true;
|
||||
}
|
||||
|
||||
field.set(object, value);
|
||||
|
||||
if (modifyAccess)
|
||||
{
|
||||
field.setAccessible(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new CliException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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.cli;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class CliRequiredException extends CliException
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param string
|
||||
*/
|
||||
public CliRequiredException(String string)
|
||||
{
|
||||
super(string);
|
||||
}
|
||||
}
|
||||
111
scm-core/src/main/java/sonia/scm/cli/ConvertUtil.java
Normal file
111
scm-core/src/main/java/sonia/scm/cli/ConvertUtil.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* 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.cli;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class ConvertUtil
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(ConvertUtil.class);
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
* @param value
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Object convertString(Class<?> type, String value)
|
||||
{
|
||||
Object result = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (type.isAssignableFrom(String.class))
|
||||
{
|
||||
result = value;
|
||||
}
|
||||
else if (type.isAssignableFrom(Short.class))
|
||||
{
|
||||
result = Short.parseShort(value);
|
||||
}
|
||||
else if (type.isAssignableFrom(Integer.class))
|
||||
{
|
||||
result = Integer.parseInt(value);
|
||||
}
|
||||
else if (type.isAssignableFrom(Long.class))
|
||||
{
|
||||
result = Long.parseLong(value);
|
||||
}
|
||||
else if (type.isAssignableFrom(BigInteger.class))
|
||||
{
|
||||
result = new BigInteger(value);
|
||||
}
|
||||
else if (type.isAssignableFrom(Float.class))
|
||||
{
|
||||
result = Float.parseFloat(value);
|
||||
}
|
||||
else if (type.isAssignableFrom(Double.class))
|
||||
{
|
||||
result = Double.parseDouble(value);
|
||||
}
|
||||
else if (type.isAssignableFrom(Boolean.class))
|
||||
{
|
||||
result = Boolean.parseBoolean(value);
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ex)
|
||||
{
|
||||
logger.debug(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
239
scm-core/src/main/java/sonia/scm/cli/DefaultCliHelpBuilder.java
Normal file
239
scm-core/src/main/java/sonia/scm/cli/DefaultCliHelpBuilder.java
Normal file
@@ -0,0 +1,239 @@
|
||||
/**
|
||||
* 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.cli;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class DefaultCliHelpBuilder implements CliHelpBuilder
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*/
|
||||
public DefaultCliHelpBuilder() {}
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param prefix
|
||||
* @param suffix
|
||||
*/
|
||||
public DefaultCliHelpBuilder(String prefix, String suffix)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param arguments
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String createHelp(List<Argument> arguments)
|
||||
{
|
||||
String s = System.getProperty("line.separator");
|
||||
int paramLength = 20;
|
||||
List<HelpLine> list = new ArrayList<HelpLine>();
|
||||
|
||||
if (arguments != null)
|
||||
{
|
||||
for (Argument argument : arguments)
|
||||
{
|
||||
HelpLine line = new HelpLine();
|
||||
String name = argument.value();
|
||||
String longName = argument.longName();
|
||||
String description = argument.description();
|
||||
StringBuilder result = new StringBuilder("-");
|
||||
|
||||
result.append(name);
|
||||
|
||||
if (longName.length() > 0)
|
||||
{
|
||||
result.append(",--").append(longName);
|
||||
}
|
||||
|
||||
line.parameter = result.toString();
|
||||
|
||||
if (line.parameter.length() > paramLength)
|
||||
{
|
||||
paramLength = line.parameter.length();
|
||||
}
|
||||
|
||||
if (description.length() > 0)
|
||||
{
|
||||
line.description = description;
|
||||
}
|
||||
|
||||
list.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
paramLength += 2;
|
||||
Collections.sort(list);
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
if ((prefix != null) && (prefix.trim().length() > 0))
|
||||
{
|
||||
result.append(prefix).append(s);
|
||||
}
|
||||
|
||||
for (HelpLine line : list)
|
||||
{
|
||||
int length = line.parameter.length();
|
||||
|
||||
result.append(line.parameter);
|
||||
|
||||
for (int i = length; i < paramLength; i++)
|
||||
{
|
||||
result.append(" ");
|
||||
}
|
||||
|
||||
result.append(line.description).append(s);
|
||||
}
|
||||
|
||||
if ((suffix != null) && (suffix.trim().length() > 0))
|
||||
{
|
||||
result.append(suffix).append(s);
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getPrefix()
|
||||
{
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getSuffix()
|
||||
{
|
||||
return suffix;
|
||||
}
|
||||
|
||||
//~--- set methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param prefix
|
||||
*/
|
||||
public void setPrefix(String prefix)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param suffix
|
||||
*/
|
||||
public void setSuffix(String suffix)
|
||||
{
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
//~--- inner classes --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class description
|
||||
*
|
||||
*
|
||||
* @version Enter version here..., 10/03/06
|
||||
* @author Enter your name here...
|
||||
*/
|
||||
private static class HelpLine implements Comparable<HelpLine>
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param o
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(HelpLine o)
|
||||
{
|
||||
return parameter.compareTo(o.parameter);
|
||||
}
|
||||
|
||||
//~--- fields -------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private String description;
|
||||
|
||||
/** Field description */
|
||||
private String parameter;
|
||||
}
|
||||
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private String prefix;
|
||||
|
||||
/** Field description */
|
||||
private String suffix;
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.repository.xml;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.xml.XmlTimestampDateAdapter;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@XmlRootElement
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class XmlRepositoryDatabase
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*/
|
||||
public void add(Repository repository)
|
||||
{
|
||||
repositoryMap.put(createKey(repository), repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
* @param name
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean contains(String type, String name)
|
||||
{
|
||||
return repositoryMap.containsKey(createKey(type, name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean contains(String id)
|
||||
{
|
||||
return get(id) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean contains(Repository repository)
|
||||
{
|
||||
return repositoryMap.containsKey(createKey(repository));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*/
|
||||
public void remove(Repository repository)
|
||||
{
|
||||
repositoryMap.remove(createKey(repository));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<Repository> values()
|
||||
{
|
||||
return repositoryMap.values();
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
* @param name
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Repository get(String type, String name)
|
||||
{
|
||||
return repositoryMap.get(createKey(type, name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Repository get(String id)
|
||||
{
|
||||
Repository repository = null;
|
||||
|
||||
for (Repository r : values())
|
||||
{
|
||||
if (r.getId().equals(id))
|
||||
{
|
||||
repository = r;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getCreationTime()
|
||||
{
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getLastModified()
|
||||
{
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
//~--- set methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param creationTime
|
||||
*/
|
||||
public void setCreationTime(long creationTime)
|
||||
{
|
||||
this.creationTime = creationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param lastModified
|
||||
*/
|
||||
public void setLastModified(long lastModified)
|
||||
{
|
||||
this.lastModified = lastModified;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
* @param name
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static String createKey(String type, String name)
|
||||
{
|
||||
return type.concat(":").concat(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static String createKey(Repository repository)
|
||||
{
|
||||
return createKey(repository.getType(), repository.getName());
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
@XmlJavaTypeAdapter(XmlTimestampDateAdapter.class)
|
||||
private Long creationTime;
|
||||
|
||||
/** Field description */
|
||||
@XmlJavaTypeAdapter(XmlTimestampDateAdapter.class)
|
||||
private Long lastModified;
|
||||
|
||||
/** Field description */
|
||||
@XmlJavaTypeAdapter(XmlRepositoryMapAdapter.class)
|
||||
@XmlElement(name = "repositories")
|
||||
private Map<String, Repository> repositoryMap = new LinkedHashMap<String,
|
||||
Repository>();
|
||||
}
|
||||
@@ -1,595 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.repository.xml;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.ConfigurationException;
|
||||
import sonia.scm.HandlerEvent;
|
||||
import sonia.scm.SCMContext;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.Type;
|
||||
import sonia.scm.repository.AbstractRepositoryManager;
|
||||
import sonia.scm.repository.PermissionType;
|
||||
import sonia.scm.repository.PermissionUtil;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryAllreadyExistExeption;
|
||||
import sonia.scm.repository.RepositoryException;
|
||||
import sonia.scm.repository.RepositoryHandler;
|
||||
import sonia.scm.repository.RepositoryHandlerNotFoundException;
|
||||
import sonia.scm.security.SecurityContext;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.util.IOUtil;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.xml.bind.JAXB;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
public class XmlRepositoryManager extends AbstractRepositoryManager
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final String DATABASEFILE =
|
||||
"config".concat(File.separator).concat("repositories.xml");
|
||||
|
||||
/** Field description */
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(XmlRepositoryManager.class);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param securityContextProvider
|
||||
* @param handlerSet
|
||||
*/
|
||||
@Inject
|
||||
public XmlRepositoryManager(
|
||||
Provider<SecurityContext> securityContextProvider,
|
||||
Set<RepositoryHandler> handlerSet)
|
||||
{
|
||||
this.securityContextProvider = securityContextProvider;
|
||||
handlerMap = new HashMap<String, RepositoryHandler>();
|
||||
types = new HashSet<Type>();
|
||||
|
||||
for (RepositoryHandler handler : handlerSet)
|
||||
{
|
||||
addHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
for (RepositoryHandler handler : handlerMap.values())
|
||||
{
|
||||
IOUtil.close(handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
@Override
|
||||
public void create(Repository repository)
|
||||
throws RepositoryException, IOException
|
||||
{
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
logger.info("create repository {} of type {}", repository.getName(),
|
||||
repository.getType());
|
||||
}
|
||||
|
||||
assertIsAdmin();
|
||||
AssertUtil.assertIsValid(repository);
|
||||
|
||||
if (repositoryDB.contains(repository))
|
||||
{
|
||||
throw new RepositoryAllreadyExistExeption();
|
||||
}
|
||||
|
||||
repository.setId(UUID.randomUUID().toString());
|
||||
repository.setCreationDate(System.currentTimeMillis());
|
||||
getHandler(repository).create(repository);
|
||||
|
||||
synchronized (XmlRepositoryDatabase.class)
|
||||
{
|
||||
repositoryDB.add(repository.clone());
|
||||
storeDB();
|
||||
}
|
||||
|
||||
fireEvent(repository, HandlerEvent.CREATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
@Override
|
||||
public void delete(Repository repository)
|
||||
throws RepositoryException, IOException
|
||||
{
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
logger.info("delete repository {} of type {}", repository.getName(),
|
||||
repository.getType());
|
||||
}
|
||||
|
||||
assertIsOwner(repository);
|
||||
|
||||
if (repositoryDB.contains(repository))
|
||||
{
|
||||
getHandler(repository).delete(repository);
|
||||
|
||||
synchronized (XmlRepositoryDatabase.class)
|
||||
{
|
||||
repositoryDB.remove(repository);
|
||||
storeDB();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RepositoryException(
|
||||
"repository ".concat(repository.getName()).concat(" not found"));
|
||||
}
|
||||
|
||||
fireEvent(repository, HandlerEvent.DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
@Override
|
||||
public void init(SCMContextProvider context)
|
||||
{
|
||||
File directory = context.getBaseDirectory();
|
||||
|
||||
repositoryDBFile = new File(directory, DATABASEFILE);
|
||||
|
||||
if (repositoryDBFile.exists())
|
||||
{
|
||||
loadDB();
|
||||
}
|
||||
else
|
||||
{
|
||||
IOUtil.mkdirs(repositoryDBFile.getParentFile());
|
||||
repositoryDB = new XmlRepositoryDatabase();
|
||||
repositoryDB.setCreationTime(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
@Override
|
||||
public void modify(Repository repository)
|
||||
throws RepositoryException, IOException
|
||||
{
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
logger.info("modify repository {} of type {}", repository.getName(),
|
||||
repository.getType());
|
||||
}
|
||||
|
||||
AssertUtil.assertIsValid(repository);
|
||||
|
||||
Repository notModifiedRepository = repositoryDB.get(repository.getType(),
|
||||
repository.getName());
|
||||
|
||||
if (notModifiedRepository != null)
|
||||
{
|
||||
assertIsOwner(notModifiedRepository);
|
||||
getHandler(repository).modify(repository);
|
||||
repository.setLastModified(System.currentTimeMillis());
|
||||
|
||||
synchronized (XmlRepositoryDatabase.class)
|
||||
{
|
||||
repositoryDB.remove(repository);
|
||||
repositoryDB.add(repository.clone());
|
||||
storeDB();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RepositoryException(
|
||||
"repository ".concat(repository.getName()).concat(" not found"));
|
||||
}
|
||||
|
||||
fireEvent(repository, HandlerEvent.MODIFY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
@Override
|
||||
public void refresh(Repository repository)
|
||||
throws RepositoryException, IOException
|
||||
{
|
||||
AssertUtil.assertIsNotNull(repository);
|
||||
assertIsReader(repository);
|
||||
|
||||
Repository fresh = repositoryDB.get(repository.getType(),
|
||||
repository.getName());
|
||||
|
||||
if (fresh != null)
|
||||
{
|
||||
fresh.copyProperties(repository);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RepositoryException(
|
||||
"repository ".concat(repository.getName()).concat(" not found"));
|
||||
}
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Repository get(String id)
|
||||
{
|
||||
AssertUtil.assertIsNotEmpty(id);
|
||||
|
||||
Repository repository = repositoryDB.get(id);
|
||||
|
||||
if (repository != null)
|
||||
{
|
||||
assertIsReader(repository);
|
||||
repository = repository.clone();
|
||||
}
|
||||
|
||||
return repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
* @param name
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Repository get(String type, String name)
|
||||
{
|
||||
AssertUtil.assertIsNotEmpty(type);
|
||||
AssertUtil.assertIsNotEmpty(name);
|
||||
|
||||
Repository repository = repositoryDB.get(type, name);
|
||||
|
||||
if (repository != null)
|
||||
{
|
||||
if (isReader(repository))
|
||||
{
|
||||
repository = repository.clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
repository = null;
|
||||
}
|
||||
}
|
||||
|
||||
return repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Collection<Repository> getAll()
|
||||
{
|
||||
LinkedList<Repository> repositories = new LinkedList<Repository>();
|
||||
|
||||
for (Repository repository : repositoryDB.values())
|
||||
{
|
||||
if (isReader(repository))
|
||||
{
|
||||
repositories.add(repository.clone());
|
||||
}
|
||||
}
|
||||
|
||||
return repositories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param type
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public RepositoryHandler getHandler(String type)
|
||||
{
|
||||
return handlerMap.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Collection<Type> getTypes()
|
||||
{
|
||||
return types;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param handler
|
||||
*/
|
||||
private void addHandler(RepositoryHandler handler)
|
||||
{
|
||||
AssertUtil.assertIsNotNull(handler);
|
||||
|
||||
Type type = handler.getType();
|
||||
|
||||
AssertUtil.assertIsNotNull(type);
|
||||
|
||||
if (handlerMap.containsKey(type.getName()))
|
||||
{
|
||||
throw new ConfigurationException(
|
||||
type.getName().concat("allready registered"));
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
logger.info("added RepositoryHandler {} for type {}", handler.getClass(),
|
||||
type);
|
||||
}
|
||||
|
||||
handlerMap.put(type.getName(), handler);
|
||||
handler.init(SCMContext.getContext());
|
||||
types.add(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
private void assertIsAdmin() throws RepositoryException
|
||||
{
|
||||
if (!getCurrentUser().isAdmin())
|
||||
{
|
||||
throw new RepositoryException("admin permsission required");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*/
|
||||
private void assertIsOwner(Repository repository)
|
||||
{
|
||||
PermissionUtil.assertPermission(repository, getCurrentUser(),
|
||||
PermissionType.OWNER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*/
|
||||
private void assertIsReader(Repository repository)
|
||||
{
|
||||
PermissionUtil.assertPermission(repository, getCurrentUser(),
|
||||
PermissionType.READ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
private void loadDB()
|
||||
{
|
||||
repositoryDB = JAXB.unmarshal(repositoryDBFile,
|
||||
XmlRepositoryDatabase.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
private void storeDB()
|
||||
{
|
||||
repositoryDB.setLastModified(System.currentTimeMillis());
|
||||
JAXB.marshal(repositoryDB, repositoryDBFile);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private User getCurrentUser()
|
||||
{
|
||||
SecurityContext context = securityContextProvider.get();
|
||||
|
||||
AssertUtil.assertIsNotNull(context);
|
||||
|
||||
User user = context.getUser();
|
||||
|
||||
AssertUtil.assertIsNotNull(user);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*
|
||||
* @return
|
||||
*
|
||||
*
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
private RepositoryHandler getHandler(Repository repository)
|
||||
throws RepositoryException
|
||||
{
|
||||
String type = repository.getType();
|
||||
RepositoryHandler handler = handlerMap.get(type);
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
throw new RepositoryHandlerNotFoundException(
|
||||
"could not find handler for ".concat(type));
|
||||
}
|
||||
else if (!handler.isConfigured())
|
||||
{
|
||||
throw new RepositoryException("handler is not configured");
|
||||
}
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean isReader(Repository repository)
|
||||
{
|
||||
return PermissionUtil.hasPermission(repository, getCurrentUser(),
|
||||
PermissionType.READ);
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private Map<String, RepositoryHandler> handlerMap;
|
||||
|
||||
/** Field description */
|
||||
private XmlRepositoryDatabase repositoryDB;
|
||||
|
||||
/** Field description */
|
||||
private File repositoryDBFile;
|
||||
|
||||
/** Field description */
|
||||
private Provider<SecurityContext> securityContextProvider;
|
||||
|
||||
/** Field description */
|
||||
private Set<Type> types;
|
||||
}
|
||||
@@ -1,388 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.user.xml;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.security.ScmSecurityException;
|
||||
import sonia.scm.security.SecurityContext;
|
||||
import sonia.scm.user.AbstractUserManager;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserAllreadyExistException;
|
||||
import sonia.scm.user.UserException;
|
||||
import sonia.scm.util.IOUtil;
|
||||
import sonia.scm.util.SecurityUtil;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import javax.xml.bind.JAXB;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
public class XmlUserManager extends AbstractUserManager
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final String ADMIN_PATH = "/sonia/scm/config/admin-account.xml";
|
||||
|
||||
/** Field description */
|
||||
public static final String DATABASEFILE =
|
||||
"config".concat(File.separator).concat("users.xml");
|
||||
|
||||
/** Field description */
|
||||
public static final String TYPE = "xml";
|
||||
|
||||
/** the logger for XmlUserManager */
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(XmlUserManager.class);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param scurityContextProvider
|
||||
*/
|
||||
@Inject
|
||||
public XmlUserManager(Provider<SecurityContext> scurityContextProvider)
|
||||
{
|
||||
this.scurityContextProvider = scurityContextProvider;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param username
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(String username)
|
||||
{
|
||||
return userDB.contains(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws UserException
|
||||
*/
|
||||
@Override
|
||||
public void create(User user) throws UserException, IOException
|
||||
{
|
||||
User currentUser = SecurityUtil.getCurrentUser(scurityContextProvider);
|
||||
|
||||
if (!user.equals(currentUser) &&!currentUser.isAdmin())
|
||||
{
|
||||
throw new ScmSecurityException("admin account is required");
|
||||
}
|
||||
|
||||
if (userDB.contains(user.getName()))
|
||||
{
|
||||
throw new UserAllreadyExistException();
|
||||
}
|
||||
|
||||
String type = user.getType();
|
||||
|
||||
if (Util.isEmpty(type))
|
||||
{
|
||||
user.setType(TYPE);
|
||||
}
|
||||
|
||||
synchronized (XmlUserManager.class)
|
||||
{
|
||||
userDB.add(user.clone());
|
||||
storeDB();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws UserException
|
||||
*/
|
||||
@Override
|
||||
public void delete(User user) throws UserException, IOException
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(scurityContextProvider);
|
||||
|
||||
String name = user.getName();
|
||||
|
||||
if (userDB.contains(name))
|
||||
{
|
||||
synchronized (XmlUserManager.class)
|
||||
{
|
||||
userDB.remove(name);
|
||||
storeDB();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new UserException("user does not exists");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
@Override
|
||||
public void init(SCMContextProvider context)
|
||||
{
|
||||
File directory = context.getBaseDirectory();
|
||||
|
||||
userDBFile = new File(directory, DATABASEFILE);
|
||||
|
||||
if (userDBFile.exists())
|
||||
{
|
||||
loadDB();
|
||||
}
|
||||
else
|
||||
{
|
||||
IOUtil.mkdirs(userDBFile.getParentFile());
|
||||
userDB = new XmlUserDatabase();
|
||||
userDB.setCreationTime(System.currentTimeMillis());
|
||||
createAdminAccount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws UserException
|
||||
*/
|
||||
@Override
|
||||
public void modify(User user) throws UserException, IOException
|
||||
{
|
||||
User currentUser = SecurityUtil.getCurrentUser(scurityContextProvider);
|
||||
|
||||
if (!user.equals(currentUser) &&!currentUser.isAdmin())
|
||||
{
|
||||
throw new ScmSecurityException("admin account is required");
|
||||
}
|
||||
|
||||
String name = user.getName();
|
||||
|
||||
if (userDB.contains(name))
|
||||
{
|
||||
synchronized (XmlUserManager.class)
|
||||
{
|
||||
userDB.remove(name);
|
||||
userDB.add(user.clone());
|
||||
storeDB();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new UserException("user does not exists");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws UserException
|
||||
*/
|
||||
@Override
|
||||
public void refresh(User user) throws UserException, IOException
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(scurityContextProvider);
|
||||
|
||||
User fresh = userDB.get(user.getName());
|
||||
|
||||
if (fresh == null)
|
||||
{
|
||||
throw new UserException("user does not exists");
|
||||
}
|
||||
|
||||
fresh.copyProperties(user);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public User get(String id)
|
||||
{
|
||||
|
||||
// SecurityUtil.assertIsAdmin(scurityContextProvider);
|
||||
User user = userDB.get(id);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
user = user.clone();
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Collection<User> getAll()
|
||||
{
|
||||
SecurityUtil.assertIsAdmin(scurityContextProvider);
|
||||
|
||||
LinkedList<User> users = new LinkedList<User>();
|
||||
|
||||
for (User user : userDB.values())
|
||||
{
|
||||
users.add(user.clone());
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
private void createAdminAccount()
|
||||
{
|
||||
InputStream input = XmlUserManager.class.getResourceAsStream(ADMIN_PATH);
|
||||
|
||||
try
|
||||
{
|
||||
User user = JAXB.unmarshal(input, User.class);
|
||||
|
||||
userDB.add(user);
|
||||
storeDB();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.error("could not create AdminAccount", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close(input);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
private void loadDB()
|
||||
{
|
||||
userDB = JAXB.unmarshal(userDBFile, XmlUserDatabase.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
private void storeDB()
|
||||
{
|
||||
userDB.setLastModified(System.currentTimeMillis());
|
||||
JAXB.marshal(userDB, userDBFile);
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private Provider<SecurityContext> scurityContextProvider;
|
||||
|
||||
/** Field description */
|
||||
private XmlUserDatabase userDB;
|
||||
|
||||
/** Field description */
|
||||
private File userDBFile;
|
||||
}
|
||||
194
scm-core/src/main/java/sonia/scm/web/cgi/AbstractCGIServlet.java
Normal file
194
scm-core/src/main/java/sonia/scm/web/cgi/AbstractCGIServlet.java
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* 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.cgi;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public abstract class AbstractCGIServlet extends HttpServlet
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
private static final long serialVersionUID = -8638099037069714140L;
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param req
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
protected abstract File getCommand(HttpServletRequest req)
|
||||
throws ServletException, IOException;
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
public void init() throws ServletException
|
||||
{
|
||||
cgiRunner = new CGIRunner(getServletContext(), getCmdPrefix(),
|
||||
isExitStateIgnored());
|
||||
baseEnvironment = createBaseEnvironment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws ServletException
|
||||
*/
|
||||
protected EnvList createBaseEnvironment() throws ServletException
|
||||
{
|
||||
EnvList env = new EnvList();
|
||||
Enumeration e = getInitParameterNames();
|
||||
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
String n = (String) e.nextElement();
|
||||
|
||||
if ((n != null) && n.startsWith("ENV_"))
|
||||
{
|
||||
env.set(n.substring(4), getInitParameter(n));
|
||||
}
|
||||
}
|
||||
|
||||
if (!env.containsKey("SystemRoot"))
|
||||
{
|
||||
String os = System.getProperty("os.name");
|
||||
|
||||
if ((os != null) && (os.toLowerCase().indexOf("windows") != -1))
|
||||
{
|
||||
env.set("SystemRoot", "C:\\WINDOWS");
|
||||
}
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param baseEnvironment
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws ServletException
|
||||
*/
|
||||
protected EnvList createRequestEnvironment(HttpServletRequest request,
|
||||
EnvList baseEnvironment)
|
||||
throws ServletException
|
||||
{
|
||||
return new EnvList(baseEnvironment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param req
|
||||
* @param resp
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
cgiRunner.exec(createRequestEnvironment(req, baseEnvironment),
|
||||
getCommand(req), req.getPathInfo(), req, resp);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected String getCmdPrefix()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected boolean isExitStateIgnored()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private EnvList baseEnvironment;
|
||||
|
||||
/** Field description */
|
||||
private CGIRunner cgiRunner;
|
||||
}
|
||||
485
scm-core/src/main/java/sonia/scm/web/cgi/CGIRunner.java
Normal file
485
scm-core/src/main/java/sonia/scm/web/cgi/CGIRunner.java
Normal file
@@ -0,0 +1,485 @@
|
||||
/**
|
||||
* 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.cgi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.util.IOUtil;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Based on org.eclipse.jetty.servlets.CGI
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*
|
||||
*/
|
||||
public class CGIRunner
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final int BUFFERSIZE = 2 * 8192;
|
||||
|
||||
/** Field description */
|
||||
private static final Logger logger = LoggerFactory.getLogger(CGIRunner.class);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* @param cmdPrefix
|
||||
* @param ignoreExitState
|
||||
*/
|
||||
public CGIRunner(ServletContext context, String cmdPrefix,
|
||||
boolean ignoreExitState)
|
||||
{
|
||||
this.context = context;
|
||||
this.cmdPrefix = cmdPrefix;
|
||||
this.ignoreExitState = ignoreExitState;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param environment
|
||||
* @param command
|
||||
* @param pathInfo
|
||||
* @param req
|
||||
* @param res
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void exec(EnvList environment, File command, String pathInfo,
|
||||
HttpServletRequest req, HttpServletResponse res)
|
||||
throws IOException
|
||||
{
|
||||
String path = command.getAbsolutePath();
|
||||
File dir = command.getParentFile();
|
||||
String scriptName = req.getRequestURI().substring(0,
|
||||
req.getRequestURI().length() - pathInfo.length());
|
||||
String scriptPath = context.getRealPath(scriptName);
|
||||
String pathTranslated = req.getPathTranslated();
|
||||
int len = req.getContentLength();
|
||||
|
||||
if (len < 0)
|
||||
{
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (Util.isEmpty(pathTranslated))
|
||||
{
|
||||
pathTranslated = path;
|
||||
}
|
||||
|
||||
// these ones are from "The WWW Common Gateway Interface Version 1.1"
|
||||
// look at :
|
||||
// http://Web.Golux.Com/coar/cgi/draft-coar-cgi-v11-03-clean.html#6.1.1
|
||||
environment.set("AUTH_TYPE", req.getAuthType());
|
||||
environment.set("CONTENT_LENGTH", Integer.toString(len));
|
||||
environment.set("CONTENT_TYPE", req.getContentType());
|
||||
environment.set("GATEWAY_INTERFACE", "CGI/1.1");
|
||||
environment.set("PATH_INFO", pathInfo);
|
||||
environment.set("PATH_TRANSLATED", pathTranslated);
|
||||
environment.set("QUERY_STRING", req.getQueryString());
|
||||
environment.set("REMOTE_ADDR", req.getRemoteAddr());
|
||||
environment.set("REMOTE_HOST", req.getRemoteHost());
|
||||
|
||||
// The identity information reported about the connection by a
|
||||
// RFC 1413 [11] request to the remote agent, if
|
||||
// available. Servers MAY choose not to support this feature, or
|
||||
// not to request the data for efficiency reasons.
|
||||
// "REMOTE_IDENT" => "NYI"
|
||||
environment.set("REMOTE_USER", req.getRemoteUser());
|
||||
environment.set("REQUEST_METHOD", req.getMethod());
|
||||
environment.set("SCRIPT_NAME", scriptName);
|
||||
environment.set("SCRIPT_FILENAME", scriptPath);
|
||||
environment.set("SERVER_NAME", req.getServerName());
|
||||
environment.set("SERVER_PORT", Integer.toString(req.getServerPort()));
|
||||
environment.set("SERVER_PROTOCOL", req.getProtocol());
|
||||
environment.set("SERVER_SOFTWARE", context.getServerInfo());
|
||||
|
||||
Enumeration enm = req.getHeaderNames();
|
||||
|
||||
while (enm.hasMoreElements())
|
||||
{
|
||||
String name = (String) enm.nextElement();
|
||||
String value = req.getHeader(name);
|
||||
|
||||
environment.set("HTTP_" + name.toUpperCase().replace('-', '_'), value);
|
||||
}
|
||||
|
||||
// these extra ones were from printenv on www.dev.nomura.co.uk
|
||||
environment.set("HTTPS", (req.isSecure()
|
||||
? "ON"
|
||||
: "OFF"));
|
||||
|
||||
// "DOCUMENT_ROOT" => root + "/docs",
|
||||
// "SERVER_URL" => "NYI - http://us0245",
|
||||
// "TZ" => System.getProperty("user.timezone"),
|
||||
// are we meant to decode args here ? or does the script get them
|
||||
// via PATH_INFO ? if we are, they should be decoded and passed
|
||||
// into exec here...
|
||||
String execCmd = path;
|
||||
|
||||
if ((execCmd.charAt(0) != '"') && (execCmd.indexOf(" ") >= 0))
|
||||
{
|
||||
execCmd = "\"" + execCmd + "\"";
|
||||
}
|
||||
|
||||
if (cmdPrefix != null)
|
||||
{
|
||||
execCmd = cmdPrefix + " " + execCmd;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("execute cgi: ".concat(execCmd));
|
||||
}
|
||||
|
||||
Process p = (dir == null)
|
||||
? Runtime.getRuntime().exec(execCmd, environment.getEnvArray())
|
||||
: Runtime.getRuntime().exec(execCmd, environment.getEnvArray(),
|
||||
dir);
|
||||
|
||||
// hook processes input to browser's output (async)
|
||||
final InputStream inFromReq = req.getInputStream();
|
||||
final OutputStream outToCgi = p.getOutputStream();
|
||||
final int inLength = len;
|
||||
|
||||
// TODO: print or log error stream
|
||||
IOUtil.copyThread(new InputStreamReader(p.getErrorStream()),
|
||||
new OutputStreamWriter(System.err));
|
||||
new Thread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (inLength > 0)
|
||||
{
|
||||
copy(inFromReq, outToCgi, inLength);
|
||||
}
|
||||
|
||||
outToCgi.close();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.debug(ex.getMessage(), ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtil.close(inFromReq);
|
||||
IOUtil.close(outToCgi);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
// hook processes output to browser's input (sync)
|
||||
// if browser closes stream, we should detect it and kill process...
|
||||
OutputStream os = null;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
// read any headers off the top of our input stream
|
||||
// NOTE: Multiline header items not supported!
|
||||
String line = null;
|
||||
InputStream inFromCgi = p.getInputStream();
|
||||
|
||||
// br=new BufferedReader(new InputStreamReader(inFromCgi));
|
||||
// while ((line=br.readLine())!=null)
|
||||
while ((line = getTextLineFromStream(inFromCgi)).length() > 0)
|
||||
{
|
||||
if (!line.startsWith("HTTP"))
|
||||
{
|
||||
int k = line.indexOf(':');
|
||||
|
||||
if (k > 0)
|
||||
{
|
||||
String key = line.substring(0, k).trim();
|
||||
String value = line.substring(k + 1).trim();
|
||||
|
||||
if ("Location".equals(key))
|
||||
{
|
||||
res.sendRedirect(res.encodeRedirectURL(value));
|
||||
}
|
||||
else if ("Status".equals(key))
|
||||
{
|
||||
String[] token = value.split(" ");
|
||||
int status = Integer.parseInt(token[0]);
|
||||
|
||||
res.setStatus(status);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// add remaining header items to our response header
|
||||
res.addHeader(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy cgi content to response stream...
|
||||
os = res.getOutputStream();
|
||||
IOUtil.copy(inFromCgi, os);
|
||||
p.waitFor();
|
||||
|
||||
if (!ignoreExitState)
|
||||
{
|
||||
int exitValue = p.exitValue();
|
||||
|
||||
if (0 != exitValue)
|
||||
{
|
||||
StringBuilder msg = new StringBuilder("Non-zero exit status (");
|
||||
|
||||
msg.append(exitValue).append(") from CGI program: ").append(path);
|
||||
logger.warn(msg.toString());
|
||||
|
||||
if (!res.isCommitted())
|
||||
{
|
||||
res.sendError(500, "Failed to exec CGI");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
||||
// browser has probably closed its input stream - we
|
||||
// terminate and clean up...
|
||||
logger.debug("CGI: Client closed connection!");
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
logger.debug("CGI: interrupted!");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (os != null)
|
||||
{
|
||||
IOUtil.close(os);
|
||||
}
|
||||
|
||||
os = null;
|
||||
p.destroy();
|
||||
|
||||
// Log.debug("CGI: terminated!");
|
||||
}
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getCmdPrefix()
|
||||
{
|
||||
return cmdPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ServletContext getContext()
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isIgnoreExitState()
|
||||
{
|
||||
return ignoreExitState;
|
||||
}
|
||||
|
||||
//~--- set methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param cmdPrefix
|
||||
*/
|
||||
public void setCmdPrefix(String cmdPrefix)
|
||||
{
|
||||
this.cmdPrefix = cmdPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public void setContext(ServletContext context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param ignoreExitState
|
||||
*/
|
||||
public void setIgnoreExitState(boolean ignoreExitState)
|
||||
{
|
||||
this.ignoreExitState = ignoreExitState;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param in
|
||||
* @param out
|
||||
* @param byteCount
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private void copy(InputStream in, OutputStream out, long byteCount)
|
||||
throws IOException
|
||||
{
|
||||
byte buffer[] = new byte[BUFFERSIZE];
|
||||
int len = BUFFERSIZE;
|
||||
|
||||
if (byteCount >= 0)
|
||||
{
|
||||
while (byteCount > 0)
|
||||
{
|
||||
int max = (byteCount < BUFFERSIZE)
|
||||
? (int) byteCount
|
||||
: BUFFERSIZE;
|
||||
|
||||
len = in.read(buffer, 0, max);
|
||||
|
||||
if (len == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
byteCount -= len;
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
len = in.read(buffer, 0, BUFFERSIZE);
|
||||
|
||||
if (len < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param is
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private String getTextLineFromStream(InputStream is) throws IOException
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
int b;
|
||||
|
||||
while ((b = is.read()) != -1 && (b != (int) '\n'))
|
||||
{
|
||||
buffer.append((char) b);
|
||||
}
|
||||
|
||||
return buffer.toString().trim();
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private String cmdPrefix;
|
||||
|
||||
/** Field description */
|
||||
private ServletContext context;
|
||||
|
||||
/** Field description */
|
||||
private boolean ignoreExitState;
|
||||
}
|
||||
@@ -29,54 +29,59 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.user.xml;
|
||||
package sonia.scm.web.cgi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@XmlRootElement(name = "users")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class XmlUserList implements Iterable<User>
|
||||
public class EnvList
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
* Constructs ...
|
||||
*
|
||||
*/
|
||||
public XmlUserList() {}
|
||||
public EnvList()
|
||||
{
|
||||
envMap = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param userMap
|
||||
* @param l
|
||||
*/
|
||||
public XmlUserList(Map<String, User> userMap)
|
||||
public EnvList(EnvList l)
|
||||
{
|
||||
this.users = new LinkedList<User>(userMap.values());
|
||||
envMap = new HashMap<String, String>(l.envMap);
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param key
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean containsKey(String key)
|
||||
{
|
||||
return envMap.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
@@ -84,40 +89,38 @@ public class XmlUserList implements Iterable<User>
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Iterator<User> iterator()
|
||||
public String toString()
|
||||
{
|
||||
return users.iterator();
|
||||
return envMap.toString();
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
* Get representation suitable for passing to exec.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public LinkedList<User> getUsers()
|
||||
public String[] getEnvArray()
|
||||
{
|
||||
return users;
|
||||
return envMap.values().toArray(new String[envMap.size()]);
|
||||
}
|
||||
|
||||
//~--- set methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Set a name/value pair, null values will be treated as an empty String
|
||||
*
|
||||
*
|
||||
* @param users
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
public void setUsers(LinkedList<User> users)
|
||||
public void set(String name, String value)
|
||||
{
|
||||
this.users = users;
|
||||
envMap.put(name, name.concat("=").concat(Util.nonNull(value)));
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "user")
|
||||
private LinkedList<User> users;
|
||||
private Map<String, String> envMap;
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* 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.filter;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.util.Util;
|
||||
import sonia.scm.web.security.WebSecurityContext;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import com.sun.jersey.core.util.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
public class BasicAuthenticationFilter extends HttpFilter
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final String AUTHENTICATION_REALM = "SONIA :: SCM Manager";
|
||||
|
||||
/** Field description */
|
||||
public static final String AUTHORIZATION_BASIC_PREFIX = "BASIC";
|
||||
|
||||
/** Field description */
|
||||
public static final String CREDENTIAL_SEPARATOR = ":";
|
||||
|
||||
/** Field description */
|
||||
public static final String HEADERVALUE_CONNECTION_CLOSE = "close";
|
||||
|
||||
/** Field description */
|
||||
public static final String HEADER_AUTHORIZATION = "Authorization";
|
||||
|
||||
/** Field description */
|
||||
public static final String HEADER_CONNECTION = "connection";
|
||||
|
||||
/** Field description */
|
||||
public static final String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param securityContextProvider
|
||||
*/
|
||||
@Inject
|
||||
public BasicAuthenticationFilter(
|
||||
Provider<WebSecurityContext> securityContextProvider)
|
||||
{
|
||||
this.securityContextProvider = securityContextProvider;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param chain
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
protected void doFilter(HttpServletRequest request,
|
||||
HttpServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
WebSecurityContext securityContext = securityContextProvider.get();
|
||||
User user = null;
|
||||
|
||||
if (securityContext != null)
|
||||
{
|
||||
if (!securityContext.isAuthenticated())
|
||||
{
|
||||
String authentication = request.getHeader(HEADER_AUTHORIZATION);
|
||||
|
||||
if (Util.isEmpty(authentication))
|
||||
{
|
||||
sendUnauthorized(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!authentication.toUpperCase().startsWith(
|
||||
AUTHORIZATION_BASIC_PREFIX))
|
||||
{
|
||||
throw new ServletException("wrong basic header");
|
||||
}
|
||||
|
||||
String token = authentication.substring(6);
|
||||
|
||||
token = new String(Base64.decode(token.getBytes()));
|
||||
|
||||
String[] credentials = token.split(CREDENTIAL_SEPARATOR);
|
||||
|
||||
user = securityContext.authenticate(request, response,
|
||||
credentials[0], credentials[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
user = securityContext.getUser();
|
||||
}
|
||||
}
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
chain.doFilter(new SecurityHttpServletRequestWrapper(request, user),
|
||||
response);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendUnauthorized(response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param response
|
||||
*/
|
||||
private void sendUnauthorized(HttpServletResponse response)
|
||||
{
|
||||
response.setHeader(HEADER_WWW_AUTHENTICATE,
|
||||
"Basic realm=\"" + AUTHENTICATION_REALM + "\"");
|
||||
response.setHeader(HEADER_CONNECTION, HEADERVALUE_CONNECTION_CLOSE);
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private Provider<WebSecurityContext> securityContextProvider;
|
||||
}
|
||||
123
scm-core/src/main/java/sonia/scm/web/filter/HttpFilter.java
Normal file
123
scm-core/src/main/java/sonia/scm/web/filter/HttpFilter.java
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 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.filter;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public abstract class HttpFilter implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param chain
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
protected abstract void doFilter(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
FilterChain chain)
|
||||
throws IOException, ServletException;
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param chain
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
if ((request instanceof HttpServletRequest)
|
||||
&& (response instanceof HttpServletResponse))
|
||||
{
|
||||
doFilter((HttpServletRequest) request, (HttpServletResponse) response,
|
||||
chain);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("request is not an http request");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param filterConfig
|
||||
*
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException
|
||||
{
|
||||
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
521
scm-core/src/main/java/sonia/scm/web/filter/LoggingFilter.java
Normal file
521
scm-core/src/main/java/sonia/scm/web/filter/LoggingFilter.java
Normal file
@@ -0,0 +1,521 @@
|
||||
/**
|
||||
* 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.filter;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
public class LoggingFilter extends HttpFilter
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(LoggingFilter.class);
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param chain
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
protected void doFilter(HttpServletRequest request,
|
||||
HttpServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
LoggingHttpServletRequest loggingRequest =
|
||||
new LoggingHttpServletRequest(request);
|
||||
LoggingHttpServletResponse loggingResponse =
|
||||
new LoggingHttpServletResponse(response);
|
||||
|
||||
logRequest(loggingRequest);
|
||||
chain.doFilter(request, response);
|
||||
logResponse(loggingResponse);
|
||||
}
|
||||
else
|
||||
{
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
private void logRequest(LoggingHttpServletRequest request)
|
||||
{
|
||||
logger.debug("**************** request ****************");
|
||||
logger.debug("Info: Request-Uri = {}", request.getRequestURI());
|
||||
logger.debug("Info: Remote-Addr = {}", request.getRemoteAddr());
|
||||
logger.debug("Info: Remote-User = {}",
|
||||
Util.nonNull(request.getRemoteUser()));
|
||||
logger.debug("Info: Content-Size = {}",
|
||||
Integer.toString(request.getContentLength()));
|
||||
logger.debug("Info: Content-Type = {}",
|
||||
Util.nonNull(request.getContentType()));
|
||||
logger.debug("Info: Method = {}", request.getMethod());
|
||||
logger.debug("Info: AuthType = {}", Util.nonNull(request.getAuthType()));
|
||||
|
||||
Enumeration headers = request.getHeaderNames();
|
||||
|
||||
while (headers.hasMoreElements())
|
||||
{
|
||||
String header = (String) headers.nextElement();
|
||||
|
||||
logger.debug("Header: {} = {}", header, request.getHeader(header));
|
||||
}
|
||||
|
||||
Cookie[] cookies = request.getCookies();
|
||||
|
||||
if (cookies != null)
|
||||
{
|
||||
for (Cookie cookie : cookies)
|
||||
{
|
||||
logger.debug("Cookie: {} = {}", cookie.getName(), cookie.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
Enumeration parameters = request.getParameterNames();
|
||||
|
||||
if (parameters != null)
|
||||
{
|
||||
while (parameters.hasMoreElements())
|
||||
{
|
||||
String parameter = (String) parameters.nextElement();
|
||||
|
||||
logger.debug("Parameter: {} = {}", parameter,
|
||||
request.getParameter(parameter));
|
||||
}
|
||||
}
|
||||
|
||||
Enumeration attributes = request.getAttributeNames();
|
||||
|
||||
if (attributes != null)
|
||||
{
|
||||
while (attributes.hasMoreElements())
|
||||
{
|
||||
String attribute = (String) attributes.nextElement();
|
||||
|
||||
logger.debug("Attribute: {} = {}", attribute,
|
||||
request.getAttribute(attribute).toString());
|
||||
}
|
||||
}
|
||||
|
||||
HttpSession session = request.getSession(true);
|
||||
|
||||
logger.debug("Session-New: {}", Boolean.toString(session.isNew()));
|
||||
|
||||
Enumeration sAttributes = session.getAttributeNames();
|
||||
|
||||
if (sAttributes != null)
|
||||
{
|
||||
while (sAttributes.hasMoreElements())
|
||||
{
|
||||
String sAttribute = (String) sAttributes.nextElement();
|
||||
|
||||
logger.debug("Session-Attribute: {} = {}", sAttribute,
|
||||
request.getSession().getAttribute(sAttribute).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param response
|
||||
*/
|
||||
private void logResponse(LoggingHttpServletResponse response)
|
||||
{
|
||||
logger.debug("**************** response ****************");
|
||||
logger.debug("status code = {}",
|
||||
Integer.toString(response.getStatusCode()));
|
||||
logger.debug("status message = {}",
|
||||
Util.nonNull(response.getStatusMessage()));
|
||||
logger.debug("charset = {}", Util.nonNull(response.getCharacterEncoding()));
|
||||
logger.debug("content-type = {}", Util.nonNull(response.getContentType()));
|
||||
logger.debug("content-length = {}",
|
||||
Integer.toString(response.getContentLength()));
|
||||
|
||||
for (Cookie cookie : response.getCookies())
|
||||
{
|
||||
logger.debug("Cookie: {} = {}", cookie.getName(), cookie.getValue());
|
||||
}
|
||||
|
||||
for (Entry<String, String> header : response.getHeaders().entrySet())
|
||||
{
|
||||
logger.debug("Header: {} = {}", header.getKey(), header.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
//~--- inner classes --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class description
|
||||
*
|
||||
*
|
||||
* @version Enter version here..., 10/09/29
|
||||
* @author Enter your name here...
|
||||
*/
|
||||
private static class LoggingHttpServletRequest
|
||||
extends HttpServletRequestWrapper
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
public LoggingHttpServletRequest(HttpServletRequest request)
|
||||
{
|
||||
super(request);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class description
|
||||
*
|
||||
*
|
||||
* @version Enter version here..., 10/09/29
|
||||
* @author Enter your name here...
|
||||
*/
|
||||
private static class LoggingHttpServletResponse
|
||||
extends HttpServletResponseWrapper
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param response
|
||||
*/
|
||||
public LoggingHttpServletResponse(HttpServletResponse response)
|
||||
{
|
||||
super(response);
|
||||
}
|
||||
|
||||
//~--- methods ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param cookie
|
||||
*/
|
||||
@Override
|
||||
public void addCookie(Cookie cookie)
|
||||
{
|
||||
cookies.add(cookie);
|
||||
super.addCookie(cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* @param date
|
||||
*/
|
||||
@Override
|
||||
public void addDateHeader(String name, long date)
|
||||
{
|
||||
headers.put(name, new Date(date).toString());
|
||||
super.addDateHeader(name, date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
@Override
|
||||
public void addHeader(String name, String value)
|
||||
{
|
||||
headers.put(name, value);
|
||||
super.addHeader(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
@Override
|
||||
public void addIntHeader(String name, int value)
|
||||
{
|
||||
headers.put(name, Integer.toString(value));
|
||||
super.addIntHeader(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param sc
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void sendError(int sc) throws IOException
|
||||
{
|
||||
this.statusCode = sc;
|
||||
super.sendError(sc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param sc
|
||||
* @param msg
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void sendError(int sc, String msg) throws IOException
|
||||
{
|
||||
this.statusCode = sc;
|
||||
this.statusMessage = msg;
|
||||
super.sendError(sc, msg);
|
||||
}
|
||||
|
||||
//~--- get methods --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getContentLength()
|
||||
{
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<Cookie> getCookies()
|
||||
{
|
||||
return cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<String, String> getHeaders()
|
||||
{
|
||||
return headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getStatusCode()
|
||||
{
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getStatusMessage()
|
||||
{
|
||||
return statusMessage;
|
||||
}
|
||||
|
||||
//~--- set methods --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param len
|
||||
*/
|
||||
@Override
|
||||
public void setContentLength(int len)
|
||||
{
|
||||
this.contentLength = len;
|
||||
super.setContentLength(len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* @param date
|
||||
*/
|
||||
@Override
|
||||
public void setDateHeader(String name, long date)
|
||||
{
|
||||
headers.put(name, new Date(date).toString());
|
||||
super.setDateHeader(name, date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
@Override
|
||||
public void setHeader(String name, String value)
|
||||
{
|
||||
headers.put(name, value);
|
||||
super.setHeader(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
@Override
|
||||
public void setIntHeader(String name, int value)
|
||||
{
|
||||
headers.put(name, Integer.toString(value));
|
||||
super.setIntHeader(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param sc
|
||||
*/
|
||||
@Override
|
||||
public void setStatus(int sc)
|
||||
{
|
||||
this.statusCode = sc;
|
||||
super.setStatus(sc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param sc
|
||||
* @param sm
|
||||
*/
|
||||
@Override
|
||||
public void setStatus(int sc, String sm)
|
||||
{
|
||||
this.statusCode = sc;
|
||||
this.statusMessage = sm;
|
||||
super.setStatus(sc, sm);
|
||||
}
|
||||
|
||||
//~--- fields -------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private int contentLength = -1;
|
||||
|
||||
/** Field description */
|
||||
private Set<Cookie> cookies = new HashSet<Cookie>();
|
||||
|
||||
/** Field description */
|
||||
private int statusCode = HttpServletResponse.SC_OK;
|
||||
|
||||
/** Field description */
|
||||
private Map<String, String> headers = new LinkedHashMap<String, String>();
|
||||
|
||||
/** Field description */
|
||||
private String statusMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* 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.filter;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.repository.PermissionType;
|
||||
import sonia.scm.repository.PermissionUtil;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.web.security.WebSecurityContext;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public abstract class PermissionFilter extends HttpFilter
|
||||
{
|
||||
|
||||
/** the logger for PermissionFilter */
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(PermissionFilter.class);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param securityContextProvider
|
||||
*/
|
||||
public PermissionFilter(Provider<WebSecurityContext> securityContextProvider)
|
||||
{
|
||||
this.securityContextProvider = securityContextProvider;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract Repository getRepository(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract boolean isWriteRequest(HttpServletRequest request);
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param chain
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
protected void doFilter(HttpServletRequest request,
|
||||
HttpServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
WebSecurityContext securityContext = securityContextProvider.get();
|
||||
|
||||
AssertUtil.assertIsNotNull(securityContext);
|
||||
|
||||
User user = securityContext.getUser();
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
Repository repository = getRepository(request);
|
||||
|
||||
if (repository != null)
|
||||
{
|
||||
boolean writeRequest = isWriteRequest(request);
|
||||
|
||||
if (PermissionUtil.hasPermission(repository, securityContext.getUser(),
|
||||
writeRequest
|
||||
? PermissionType.WRITE
|
||||
: PermissionType.READ))
|
||||
{
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
logger.info("{} access to repostitory {} for user {} denied",
|
||||
new Object[] { writeRequest
|
||||
? "write"
|
||||
: "read", repository.getName(),
|
||||
user.getName() });
|
||||
}
|
||||
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("repository not found");
|
||||
}
|
||||
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("user in not authenticated");
|
||||
}
|
||||
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
protected Provider<WebSecurityContext> securityContextProvider;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* 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.filter;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.web.security.WebSecurityContext;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public abstract class RegexPermissionFilter extends PermissionFilter
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final Pattern PATTERN_REPOSITORYNAME =
|
||||
Pattern.compile("/[^/]+/([^/]+)(?:/.*)?");
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param securityContextProvider
|
||||
* @param repositoryManager
|
||||
*/
|
||||
public RegexPermissionFilter(
|
||||
Provider<WebSecurityContext> securityContextProvider,
|
||||
RepositoryManager repositoryManager)
|
||||
{
|
||||
super(securityContextProvider);
|
||||
this.repositoryManager = repositoryManager;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract String getType();
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected Repository getRepository(HttpServletRequest request)
|
||||
{
|
||||
Repository repository = null;
|
||||
String uri = request.getRequestURI();
|
||||
|
||||
uri = uri.substring(request.getContextPath().length());
|
||||
|
||||
Matcher m = PATTERN_REPOSITORYNAME.matcher(uri);
|
||||
|
||||
if (m.matches())
|
||||
{
|
||||
String repositoryname = m.group(1);
|
||||
|
||||
repository = getRepository(repositoryname);
|
||||
}
|
||||
|
||||
return repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected Repository getRepository(String name)
|
||||
{
|
||||
return repositoryManager.get(getType(), name);
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private RepositoryManager repositoryManager;
|
||||
}
|
||||
@@ -29,69 +29,79 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.repository.xml;
|
||||
package sonia.scm.web.filter;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.user.User;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.security.Principal;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class XmlRepositoryMapAdapter
|
||||
extends XmlAdapter<XmlRepositoryList, Map<String, Repository>>
|
||||
public class SecurityHttpServletRequestWrapper extends HttpServletRequestWrapper
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param user
|
||||
*/
|
||||
public SecurityHttpServletRequestWrapper(HttpServletRequest request,
|
||||
User user)
|
||||
{
|
||||
super(request);
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repositoryMap
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public XmlRepositoryList marshal(Map<String, Repository> repositoryMap)
|
||||
throws Exception
|
||||
public String getRemoteUser()
|
||||
{
|
||||
return new XmlRepositoryList(repositoryMap);
|
||||
return user.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repositories
|
||||
* @return
|
||||
*/
|
||||
public User getUser()
|
||||
{
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Repository> unmarshal(XmlRepositoryList repositories)
|
||||
throws Exception
|
||||
public Principal getUserPrincipal()
|
||||
{
|
||||
Map<String, Repository> repositoryMap = new LinkedHashMap<String,
|
||||
Repository>();
|
||||
|
||||
for (Repository repository : repositories)
|
||||
{
|
||||
repositoryMap.put(XmlRepositoryDatabase.createKey(repository),
|
||||
repository);
|
||||
}
|
||||
|
||||
return repositoryMap;
|
||||
return user;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private User user;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.web.security;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.Initable;
|
||||
import sonia.scm.TypedObject;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public interface AuthenticationHandler extends Initable, Closeable, TypedObject
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param username
|
||||
* @param password
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public AuthenticationResult authenticate(HttpServletRequest request,
|
||||
HttpServletResponse response, String username, String password);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.web.security;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.Initable;
|
||||
import sonia.scm.user.User;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public interface AuthenticationManager extends Initable, Closeable
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param username
|
||||
* @param password
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public User authenticate(HttpServletRequest request,
|
||||
HttpServletResponse response, String username,
|
||||
String password);
|
||||
}
|
||||
@@ -31,48 +31,64 @@
|
||||
|
||||
|
||||
|
||||
package sonia.scm.repository.xml;
|
||||
package sonia.scm.web.security;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.repository.Repository;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import sonia.scm.user.User;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@XmlRootElement(name = "repositories")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class XmlRepositoryList implements Iterable<Repository>
|
||||
public class AuthenticationResult
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final AuthenticationResult NOT_FOUND =
|
||||
new AuthenticationResult(AuthenticationState.NOT_FOUND);
|
||||
|
||||
/** Field description */
|
||||
public static final AuthenticationResult FAILED =
|
||||
new AuthenticationResult(AuthenticationState.FAILED);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param state
|
||||
*/
|
||||
public XmlRepositoryList() {}
|
||||
public AuthenticationResult(AuthenticationState state)
|
||||
{
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param repositoryMap
|
||||
* @param user
|
||||
*/
|
||||
public XmlRepositoryList(Map<String, Repository> repositoryMap)
|
||||
public AuthenticationResult(User user)
|
||||
{
|
||||
this.repositories = new LinkedList<Repository>(repositoryMap.values());
|
||||
this.user = user;
|
||||
this.state = AuthenticationState.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
* @param state
|
||||
*/
|
||||
public AuthenticationResult(User user, AuthenticationState state)
|
||||
{
|
||||
this.user = user;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
@@ -84,9 +100,20 @@ public class XmlRepositoryList implements Iterable<Repository>
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Repository> iterator()
|
||||
public String toString()
|
||||
{
|
||||
return repositories.iterator();
|
||||
StringBuilder out = new StringBuilder("user: ");
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
out.append(user.getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
out.append("null");
|
||||
}
|
||||
|
||||
return out.append(", state: ").append(state.toString()).toString();
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
@@ -97,27 +124,27 @@ public class XmlRepositoryList implements Iterable<Repository>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public LinkedList<Repository> getRepositories()
|
||||
public AuthenticationState getState()
|
||||
{
|
||||
return repositories;
|
||||
return state;
|
||||
}
|
||||
|
||||
//~--- set methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repositories
|
||||
* @return
|
||||
*/
|
||||
public void setRepositories(LinkedList<Repository> repositories)
|
||||
public User getUser()
|
||||
{
|
||||
this.repositories = repositories;
|
||||
return user;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
@XmlElement(name = "repository")
|
||||
private LinkedList<Repository> repositories;
|
||||
private AuthenticationState state;
|
||||
|
||||
/** Field description */
|
||||
private User user;
|
||||
}
|
||||
@@ -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.web.security;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public enum AuthenticationState
|
||||
{
|
||||
SUCCESS(true), NOT_FOUND(false), FAILED(false);
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param successfully
|
||||
*/
|
||||
private AuthenticationState(boolean successfully)
|
||||
{
|
||||
this.successfully = successfully;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isSuccessfully()
|
||||
{
|
||||
return successfully;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private boolean successfully = false;
|
||||
}
|
||||
@@ -31,80 +31,117 @@
|
||||
|
||||
|
||||
|
||||
package sonia.scm.user.xml;
|
||||
package sonia.scm.web.security;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.servlet.SessionScoped;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.xml.XmlTimestampDateAdapter;
|
||||
import sonia.scm.user.UserManager;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@XmlRootElement(name = "user-db")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class XmlUserDatabase
|
||||
@SessionScoped
|
||||
public class BasicSecurityContext implements WebSecurityContext
|
||||
{
|
||||
|
||||
/** the logger for BasicSecurityContext */
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(BasicSecurityContext.class);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
* @param authenticator
|
||||
* @param userManager
|
||||
*/
|
||||
public void add(User user)
|
||||
@Inject
|
||||
public BasicSecurityContext(AuthenticationManager authenticator,
|
||||
UserManager userManager)
|
||||
{
|
||||
userMap.put(user.getName(), user);
|
||||
this.authenticator = authenticator;
|
||||
this.userManager = userManager;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param username
|
||||
* @param password
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean contains(String username)
|
||||
@Override
|
||||
public User authenticate(HttpServletRequest request,
|
||||
HttpServletResponse response, String username,
|
||||
String password)
|
||||
{
|
||||
return userMap.containsKey(username);
|
||||
user = authenticator.authenticate(request, response, username, password);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
user.setLastLogin(System.currentTimeMillis());
|
||||
|
||||
User dbUser = userManager.get(username);
|
||||
|
||||
if (dbUser != null)
|
||||
{
|
||||
|
||||
// update properties
|
||||
dbUser.setDisplayName(user.getDisplayName());
|
||||
dbUser.setLastLogin(user.getLastLogin());
|
||||
dbUser.setMail(user.getMail());
|
||||
dbUser.setType(user.getType());
|
||||
userManager.modify(dbUser);
|
||||
}
|
||||
else
|
||||
{
|
||||
userManager.create(user);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
user = null;
|
||||
logger.error(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param username
|
||||
*
|
||||
* @return
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
public User remove(String username)
|
||||
@Override
|
||||
public void logout(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
return userMap.remove(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<User> values()
|
||||
{
|
||||
return userMap.values();
|
||||
user = null;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
@@ -113,13 +150,12 @@ public class XmlUserDatabase
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param username
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public User get(String username)
|
||||
@Override
|
||||
public User getUser()
|
||||
{
|
||||
return userMap.get(username);
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,58 +164,20 @@ public class XmlUserDatabase
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getCreationTime()
|
||||
@Override
|
||||
public boolean isAuthenticated()
|
||||
{
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getLastModified()
|
||||
{
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
//~--- set methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param creationTime
|
||||
*/
|
||||
public void setCreationTime(long creationTime)
|
||||
{
|
||||
this.creationTime = creationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param lastModified
|
||||
*/
|
||||
public void setLastModified(long lastModified)
|
||||
{
|
||||
this.lastModified = lastModified;
|
||||
return user != null;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
@XmlJavaTypeAdapter(XmlTimestampDateAdapter.class)
|
||||
private Long creationTime;
|
||||
private AuthenticationManager authenticator;
|
||||
|
||||
/** Field description */
|
||||
@XmlJavaTypeAdapter(XmlTimestampDateAdapter.class)
|
||||
private Long lastModified;
|
||||
private User user;
|
||||
|
||||
/** Field description */
|
||||
@XmlJavaTypeAdapter(XmlUserMapAdapter.class)
|
||||
@XmlElement(name = "users")
|
||||
private Map<String, User> userMap = new LinkedHashMap<String, User>();
|
||||
private UserManager userManager;
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.web.security;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.util.IOUtil;
|
||||
|
||||
//~--- 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 ChainAuthenticatonManager implements AuthenticationManager
|
||||
{
|
||||
|
||||
/** the logger for ChainAuthenticatonManager */
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(ChainAuthenticatonManager.class);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param authenticationHandlerSet
|
||||
*/
|
||||
@Inject
|
||||
public ChainAuthenticatonManager(
|
||||
Set<AuthenticationHandler> authenticationHandlerSet)
|
||||
{
|
||||
AssertUtil.assertIsNotEmpty(authenticationHandlerSet);
|
||||
this.authenticationHandlerSet = authenticationHandlerSet;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param username
|
||||
* @param password
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public User authenticate(HttpServletRequest request,
|
||||
HttpServletResponse response, String username,
|
||||
String password)
|
||||
{
|
||||
User user = null;
|
||||
|
||||
for (AuthenticationHandler authenticator : authenticationHandlerSet)
|
||||
{
|
||||
try
|
||||
{
|
||||
AuthenticationResult result = authenticator.authenticate(request,
|
||||
response, username, password);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("authenticator {} ends with result, {}",
|
||||
authenticator.getClass().getName(), result);
|
||||
}
|
||||
|
||||
if ((result != null) && (result.getState() != null)
|
||||
&& (result.getState().isSuccessfully()
|
||||
|| (result.getState() == AuthenticationState.FAILED)))
|
||||
{
|
||||
if (result.getState().isSuccessfully() && (result.getUser() != null))
|
||||
{
|
||||
user = result.getUser();
|
||||
user.setType(authenticator.getType());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.error(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
for (AuthenticationHandler authenticator : authenticationHandlerSet)
|
||||
{
|
||||
IOUtil.close(authenticator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
@Override
|
||||
public void init(SCMContextProvider context)
|
||||
{
|
||||
for (AuthenticationHandler authenticator : authenticationHandlerSet)
|
||||
{
|
||||
authenticator.init(context);
|
||||
}
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private Set<AuthenticationHandler> authenticationHandlerSet;
|
||||
}
|
||||
@@ -31,63 +31,56 @@
|
||||
|
||||
|
||||
|
||||
package sonia.scm.user.xml;
|
||||
package sonia.scm.web.security;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.security.SecurityContext;
|
||||
import sonia.scm.user.User;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class XmlUserMapAdapter
|
||||
extends XmlAdapter<XmlUserList, Map<String, User>>
|
||||
public interface WebSecurityContext extends SecurityContext
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param userMap
|
||||
* @param request
|
||||
* @param response
|
||||
* @param username
|
||||
* @param password
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public XmlUserList marshal(Map<String, User> userMap) throws Exception
|
||||
{
|
||||
return new XmlUserList(userMap);
|
||||
}
|
||||
public User authenticate(HttpServletRequest request,
|
||||
HttpServletResponse response, String username,
|
||||
String password);
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param users
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
public void logout(HttpServletRequest request, HttpServletResponse response);
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public Map<String, User> unmarshal(XmlUserList users) throws Exception
|
||||
{
|
||||
Map<String, User> userMap = new LinkedHashMap<String, User>();
|
||||
|
||||
for (User user : users)
|
||||
{
|
||||
userMap.put(user.getName(), user);
|
||||
}
|
||||
|
||||
return userMap;
|
||||
}
|
||||
public boolean isAuthenticated();
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.web.security;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.security.EncryptionHandler;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserManager;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
public class XmlAuthenticationHandler implements AuthenticationHandler
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
public static final String NAME_DIRECTORY = "users";
|
||||
|
||||
/** Field description */
|
||||
public static final String TYPE = "xml";
|
||||
|
||||
/** the logger for XmlAuthenticationHandler */
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(XmlAuthenticationHandler.class);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param userManager
|
||||
* @param encryptionHandler
|
||||
*/
|
||||
@Inject
|
||||
public XmlAuthenticationHandler(UserManager userManager,
|
||||
EncryptionHandler encryptionHandler)
|
||||
{
|
||||
this.userManager = userManager;
|
||||
this.encryptionHandler = encryptionHandler;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param username
|
||||
* @param password
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public AuthenticationResult authenticate(HttpServletRequest request,
|
||||
HttpServletResponse response, String username, String password)
|
||||
{
|
||||
AuthenticationResult result = null;
|
||||
User user = userManager.get(username);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
if (TYPE.equals(user.getType()))
|
||||
{
|
||||
result = authenticate(user, username, password);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("{} is not an xml user", username);
|
||||
}
|
||||
|
||||
result = AuthenticationResult.NOT_FOUND;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("could not find user {}", username);
|
||||
}
|
||||
|
||||
result = AuthenticationResult.NOT_FOUND;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param provider
|
||||
*/
|
||||
@Override
|
||||
public void init(SCMContextProvider provider)
|
||||
{
|
||||
|
||||
// do nothing
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
* @param username
|
||||
* @param password
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private AuthenticationResult authenticate(User user, String username,
|
||||
String password)
|
||||
{
|
||||
AuthenticationResult result = null;
|
||||
String encryptedPassword = encryptionHandler.encrypt(password);
|
||||
|
||||
if (!encryptedPassword.equalsIgnoreCase(user.getPassword()))
|
||||
{
|
||||
user = null;
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("password for user {} is wrong", username);
|
||||
}
|
||||
|
||||
result = AuthenticationResult.FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("user {} logged in successfully", username);
|
||||
}
|
||||
|
||||
user.setPassword(null);
|
||||
result = new AuthenticationResult(user, AuthenticationState.SUCCESS);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private EncryptionHandler encryptionHandler;
|
||||
|
||||
/** Field description */
|
||||
private UserManager userManager;
|
||||
}
|
||||
Reference in New Issue
Block a user