From 95f1b3e4307fb7d407ad0cb83869af2564a1aae8 Mon Sep 17 00:00:00 2001 From: Martin Stockhammer Date: Mon, 30 Jan 2017 20:37:15 +0100 Subject: [PATCH] Implementing Header verification for REST API calls Implementing header verification techniques mentioned in: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Verifying_Same_Origin_with_Standard_Headers --- .../redback/config-defaults.properties | 6 + .../RequestValidationInterceptor.java | 213 ++++++++++++++++++ .../resources/META-INF/spring-context.xml | 1 + .../services/AbstractRestServicesTest.java | 5 + .../RequestValidationInterceptorTest.java | 162 +++++++++++++ .../rest/services/UserServiceTest.java | 3 + .../mock/MockContainerRequestContext.java | 175 ++++++++++++++ .../services/mock/MockUserConfiguration.java | 105 +++++++++ 8 files changed, 670 insertions(+) create mode 100644 redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/RequestValidationInterceptor.java create mode 100644 redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/RequestValidationInterceptorTest.java create mode 100644 redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockContainerRequestContext.java create mode 100644 redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockUserConfiguration.java diff --git a/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties b/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties index 402aaf97..9fa02ce6 100644 --- a/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties +++ b/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties @@ -133,4 +133,10 @@ ldap.bind.authenticator.enabled=false user.manager.impl=jdo +# REST security settings +# REST base url is for avoiding CSRF attacks +# If it is not set or empty it tries to determine the base url automatically +rest.baseUrl= +# If true, requests without Origin or Referer Header are denied +rest.csrf.absentorigin.deny=true \ No newline at end of file diff --git a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/RequestValidationInterceptor.java b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/RequestValidationInterceptor.java new file mode 100644 index 00000000..4300baf8 --- /dev/null +++ b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/RequestValidationInterceptor.java @@ -0,0 +1,213 @@ +package org.apache.archiva.redback.rest.services.interceptors; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +import org.apache.archiva.redback.configuration.UserConfiguration; +import org.apache.cxf.jaxrs.utils.JAXRSUtils; +import org.apache.cxf.message.Message; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Created by Martin Stockhammer on 19.01.17. + * + * This interceptor tries to check if requests come from a valid origin and + * are not generated by another site on behalf of the real client. + * + * We are using some of the techniques mentioned in + * https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet + * + * Try to find Origin and Referer of the request. + * Match them to the target address, that may be either statically configured or is determined + * by the Host/X-Forwarded-For Header. + * + * + */ +@Provider +@Service( "requestValidationInterceptor#rest" ) +public class RequestValidationInterceptor extends AbstractInterceptor implements ContainerRequestFilter { + + + private static final String X_FORWARDED_PROTO = "X-Forwarded-Proto"; + private static final String X_FORWARDED_HOST = "X-Forwarded-Host"; + private static final String ORIGIN = "Origin"; + private static final String REFERER = "Referer"; + private static final String CFG_REST_BASE_URL = "rest.baseUrl"; + private static final String CFG_REST_CSRF_ABSENTORIGIN_DENY = "rest.csrffilter.absentorigin.deny"; + private static final String CFG_REST_CSRF_ENABLED = "rest.csrffilter.enabled"; + + private final Logger log = LoggerFactory.getLogger( getClass() ); + + private boolean enabled = true; + private boolean useStaticUrl = false; + private boolean denyAbsentHeaders = true; + private URL baseUrl; + private HttpServletRequest httpRequest = null; + + private UserConfiguration config; + + @Inject + public RequestValidationInterceptor(@Named( value = "userConfiguration#default" ) + UserConfiguration config) { + this.config = config; + } + + @PostConstruct + public void init() { + String baseUrlStr = config.getString(CFG_REST_BASE_URL, ""); + if (!"".equals(baseUrlStr.trim())) { + try { + baseUrl = new URL(baseUrlStr); + useStaticUrl = true; + } catch (MalformedURLException ex) { + log.error("Configured baseUrl (rest.baseUrl={}) is invalid. Message: {}", baseUrlStr, ex.getMessage()); + } + } else { + useStaticUrl = false; + } + denyAbsentHeaders = config.getBoolean(CFG_REST_CSRF_ABSENTORIGIN_DENY,true); + enabled = config.getBoolean(CFG_REST_CSRF_ENABLED,true); + if (!enabled) { + log.info("CSRF Filter is disabled by configuration"); + } + } + + @Override + public void filter(ContainerRequestContext containerRequestContext) throws IOException { + if (enabled) { + HttpServletRequest request = getRequest(); + URL targetUrl = getTargetUrl(request); + if (targetUrl == null) { + log.error("Could not verify target URL."); + containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build()); + } + if (!checkSourceRequestHeader(targetUrl, request)) { + log.warn("HTTP Header check failed. Assuming CSRF attack."); + containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build()); + } + } + } + + private HttpServletRequest getRequest() { + if (httpRequest!=null) { + return httpRequest; + } else { + Message message = JAXRSUtils.getCurrentMessage(); + return getHttpServletRequest(message); + } + } + + private URL getTargetUrl(HttpServletRequest request) { + if (useStaticUrl) { + return baseUrl; + } else { + URL requestUrl; + try { + requestUrl = new URL(request.getRequestURL().toString()); + } catch (MalformedURLException ex) { + log.error("Bad Request URL {}, Message: {}", request.getRequestURL(), ex.getMessage()); + return null; + } + String xforwarded = request.getHeader(X_FORWARDED_HOST); + String xforwardedProto = request.getHeader(X_FORWARDED_PROTO); + if (xforwardedProto==null) { + xforwardedProto=requestUrl.getProtocol(); + } + if (xforwarded!=null) { + try { + return new URL(xforwardedProto+"://"+xforwarded); + } catch (MalformedURLException ex) { + log.warn("X-Forwarded-Host Header is malformed: {}", ex.getMessage()); + } + } + return requestUrl; + } + } + + private int getPort(final URL url) { + return url.getPort() > 0 ? url.getPort() : url.getDefaultPort(); + } + + private boolean checkSourceRequestHeader(final URL targetUrl, final HttpServletRequest request) { + boolean headerFound=false; + String origin = request.getHeader(ORIGIN); + if (origin!=null) { + try { + URL originUrl = new URL(origin); + headerFound=true; + log.debug("Origin Header URL found: {}", originUrl); + if (!targetUrl.getProtocol().equals(originUrl.getProtocol())) { + log.warn("Origin Header Protocol does not match originUrl={}, targetUrl={}", originUrl, targetUrl); + return false; + } + if (!targetUrl.getHost().equals(originUrl.getHost())) { + log.warn("Origin Header Host does not match originUrl={}, targetUrl={}",originUrl,targetUrl); + return false; + } + int originPort = getPort(originUrl); + int targetPort = getPort(targetUrl); + if (targetPort != originPort) { + log.warn("Origin Header Port does not match originUrl={}, targetUrl={}",originUrl,targetUrl); + return false; + } + } catch (MalformedURLException ex) { + log.warn("Bad URL in Origin HTTP-Header: {}. Message: {}",origin, ex.getMessage()); + return false; + } + } + String referer = request.getHeader(REFERER); + if (referer!=null) { + try { + URL refererUrl = new URL(referer); + headerFound=true; + log.debug("Referer Header URL found: {}",refererUrl); + if (!targetUrl.getHost().equals(refererUrl.getHost())) { + log.warn("Referer Header Host does not match refererUrl={}, targetUrl={}",refererUrl,targetUrl); + return false; + } + } catch (MalformedURLException ex) { + log.warn("Bad URL in Referer HTTP-Header: {}, Message: {}", referer, ex.getMessage()); + return false; + } + } + if (!headerFound && denyAbsentHeaders) { + log.warn("Neither Origin nor Referer header found. Request is denied."); + return false; + } + return true; + } + + public void setHttpRequest(HttpServletRequest request) { + this.httpRequest = request; + } +} diff --git a/redback-integrations/redback-rest/redback-rest-services/src/main/resources/META-INF/spring-context.xml b/redback-integrations/redback-rest/redback-rest-services/src/main/resources/META-INF/spring-context.xml index 98188f44..4e7b8157 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/main/resources/META-INF/spring-context.xml +++ b/redback-integrations/redback-rest/redback-rest-services/src/main/resources/META-INF/spring-context.xml @@ -65,6 +65,7 @@ + diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/AbstractRestServicesTest.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/AbstractRestServicesTest.java index 806f3220..0cab0725 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/AbstractRestServicesTest.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/AbstractRestServicesTest.java @@ -175,6 +175,7 @@ public abstract class AbstractRestServicesTest { WebClient.client( service ).header( "Authorization", authzHeader ); } + WebClient.client(service).header("Referer","http://localhost"); WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE ); WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE ); @@ -196,6 +197,8 @@ public abstract class AbstractRestServicesTest { WebClient.client( service ).header( "Authorization", authzHeader ); } + WebClient.client( service ).header("Referer","http://localhost/"); + WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE ); WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE ); @@ -216,6 +219,7 @@ public abstract class AbstractRestServicesTest { WebClient.client( service ).header( "Authorization", authzHeader ); } + WebClient.client( service ).header("Referer","http://localhost/"); WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE ); WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE ); @@ -238,6 +242,7 @@ public abstract class AbstractRestServicesTest { WebClient.client( service ).header( "Authorization", authzHeader ); } + WebClient.client( service ).header("Referer","http://localhost/"); WebClient.client( service ).accept( MediaType.APPLICATION_JSON_TYPE ); WebClient.client( service ).type( MediaType.APPLICATION_JSON_TYPE ); diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/RequestValidationInterceptorTest.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/RequestValidationInterceptorTest.java new file mode 100644 index 00000000..c88492a0 --- /dev/null +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/RequestValidationInterceptorTest.java @@ -0,0 +1,162 @@ +package org.apache.archiva.redback.rest.services; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +import junit.framework.TestCase; +import org.apache.archiva.redback.configuration.UserConfigurationException; +import org.apache.archiva.redback.rest.services.interceptors.RequestValidationInterceptor; +import org.apache.archiva.redback.rest.services.mock.MockContainerRequestContext; +import org.apache.archiva.redback.rest.services.mock.MockUserConfiguration; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.springframework.mock.web.MockHttpServletRequest; + +import java.io.IOException; + + + +/** + * Created by Martin Stockhammer on 21.01.17. + * + * Unit Test for RequestValidationInterceptor. + * + */ +@RunWith(JUnit4.class) +public class RequestValidationInterceptorTest extends TestCase { + + + + @Test + public void validateRequestWithoutHeader() throws UserConfigurationException, IOException { + MockUserConfiguration cfg = new MockUserConfiguration(); + RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg); + MockHttpServletRequest request = new MockHttpServletRequest(); + interceptor.setHttpRequest(request); + interceptor.init(); + MockContainerRequestContext ctx = new MockContainerRequestContext(); + interceptor.filter(ctx); + assertTrue(ctx.isAborted()); + } + + @Test + public void validateRequestWithOrigin() throws UserConfigurationException, IOException { + MockUserConfiguration cfg = new MockUserConfiguration(); + RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg); + MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService"); + request.setServerName("test.archiva.org"); + request.addHeader("Origin","http://test.archiva.org/myservlet"); + interceptor.setHttpRequest(request); + interceptor.init(); + MockContainerRequestContext ctx = new MockContainerRequestContext(); + interceptor.filter(ctx); + assertFalse(ctx.isAborted()); + } + + @Test + public void validateRequestWithBadOrigin() throws UserConfigurationException, IOException { + MockUserConfiguration cfg = new MockUserConfiguration(); + RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg); + MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService"); + request.setServerName("test.archiva.org"); + request.addHeader("Origin","http://test2.archiva.org/myservlet"); + interceptor.setHttpRequest(request); + interceptor.init(); + MockContainerRequestContext ctx = new MockContainerRequestContext(); + interceptor.filter(ctx); + assertTrue(ctx.isAborted()); + } + + @Test + public void validateRequestWithReferer() throws UserConfigurationException, IOException { + MockUserConfiguration cfg = new MockUserConfiguration(); + RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg); + MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService"); + request.setServerName("test.archiva.org"); + request.addHeader("Referer","http://test.archiva.org/myservlet2"); + interceptor.setHttpRequest(request); + interceptor.init(); + MockContainerRequestContext ctx = new MockContainerRequestContext(); + interceptor.filter(ctx); + assertFalse(ctx.isAborted()); + } + + @Test + public void validateRequestWithBadReferer() throws UserConfigurationException, IOException { + MockUserConfiguration cfg = new MockUserConfiguration(); + RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg); + MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService"); + request.setServerName("test.archiva.org"); + request.addHeader("Referer","http://test3.archiva.org/myservlet2"); + interceptor.setHttpRequest(request); + interceptor.init(); + MockContainerRequestContext ctx = new MockContainerRequestContext(); + interceptor.filter(ctx); + assertTrue(ctx.isAborted()); + } + + @Test + public void validateRequestWithOriginAndReferer() throws UserConfigurationException, IOException { + MockUserConfiguration cfg = new MockUserConfiguration(); + RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg); + MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService"); + request.setServerName("test.archiva.org"); + request.addHeader("Origin","http://test.archiva.org/myservlet"); + request.addHeader("Referer","http://test.archiva.org/myservlet2"); + interceptor.setHttpRequest(request); + interceptor.init(); + MockContainerRequestContext ctx = new MockContainerRequestContext(); + interceptor.filter(ctx); + assertFalse(ctx.isAborted()); + } + + + @Test + public void validateRequestWithOriginAndStaticUrl() throws UserConfigurationException, IOException { + MockUserConfiguration cfg = new MockUserConfiguration(); + cfg.addValue("rest.baseUrl","http://test.archiva.org"); + RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg); + MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService"); + request.setServerName("test4.archiva.org"); + request.addHeader("Origin","http://test.archiva.org/myservlet"); + interceptor.setHttpRequest(request); + interceptor.init(); + MockContainerRequestContext ctx = new MockContainerRequestContext(); + interceptor.filter(ctx); + assertFalse(ctx.isAborted()); + } + + @Test + public void validateRequestWithBadOriginAndStaticUrl() throws UserConfigurationException, IOException { + MockUserConfiguration cfg = new MockUserConfiguration(); + cfg.addValue("rest.baseUrl","http://mytest.archiva.org"); + RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg); + MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService"); + request.setServerName("mytest.archiva.org"); + request.addHeader("Origin","http://test.archiva.org/myservlet"); + interceptor.setHttpRequest(request); + interceptor.init(); + MockContainerRequestContext ctx = new MockContainerRequestContext(); + interceptor.filter(ctx); + assertTrue(ctx.isAborted()); + } + + +} diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/UserServiceTest.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/UserServiceTest.java index b5a80d27..a1d6f572 100644 --- a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/UserServiceTest.java +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/UserServiceTest.java @@ -93,6 +93,9 @@ public class UserServiceTest throws Exception { + UserService userService = getUserService(); + WebClient.client( userService ).header( "Origin", "http://localhost/myrequest"); + try { getFakeCreateAdminService().testAuthzWithoutKarmasNeededButAuthz(); diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockContainerRequestContext.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockContainerRequestContext.java new file mode 100644 index 00000000..ae98a8fa --- /dev/null +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockContainerRequestContext.java @@ -0,0 +1,175 @@ +package org.apache.archiva.redback.rest.services.mock; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.core.Cookie; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; +import javax.ws.rs.core.UriInfo; +import java.io.InputStream; +import java.net.URI; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * Created by Martin Stockhammer on 21.01.17. + * + * RequestContext used in unit tests. + */ +public class MockContainerRequestContext implements ContainerRequestContext { + + private boolean aborted = false; + + @Override + public Object getProperty(String s) { + return null; + } + + @Override + public Collection getPropertyNames() { + return null; + } + + @Override + public void setProperty(String s, Object o) { + + } + + @Override + public void removeProperty(String s) { + + } + + @Override + public UriInfo getUriInfo() { + return null; + } + + @Override + public void setRequestUri(URI uri) { + + } + + @Override + public void setRequestUri(URI uri, URI uri1) { + + } + + @Override + public Request getRequest() { + return null; + } + + + @Override + public String getMethod() { + return null; + } + + @Override + public void setMethod(String s) { + + } + + @Override + public MultivaluedMap getHeaders() { + return null; + } + + @Override + public String getHeaderString(String s) { + return null; + } + + @Override + public Date getDate() { + return null; + } + + @Override + public Locale getLanguage() { + return null; + } + + @Override + public int getLength() { + return 0; + } + + @Override + public MediaType getMediaType() { + return null; + } + + @Override + public List getAcceptableMediaTypes() { + return null; + } + + @Override + public List getAcceptableLanguages() { + return null; + } + + @Override + public Map getCookies() { + return null; + } + + @Override + public boolean hasEntity() { + return false; + } + + @Override + public InputStream getEntityStream() { + return null; + } + + @Override + public void setEntityStream(InputStream inputStream) { + + } + + @Override + public SecurityContext getSecurityContext() { + return null; + } + + @Override + public void setSecurityContext(SecurityContext securityContext) { + + } + + @Override + public void abortWith(Response response) { + this.aborted=true; + } + + public boolean isAborted() { + return aborted; + } +} diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockUserConfiguration.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockUserConfiguration.java new file mode 100644 index 00000000..6eaaed8f --- /dev/null +++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockUserConfiguration.java @@ -0,0 +1,105 @@ +package org.apache.archiva.redback.rest.services.mock; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +import org.apache.archiva.redback.configuration.UserConfiguration; +import org.apache.archiva.redback.configuration.UserConfigurationException; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Created by Martin Stockhammer on 21.01.17. + * + * User configuration implementation to be used in unit tests. + * + */ +public class MockUserConfiguration implements UserConfiguration { + + private Map values = new java.util.HashMap(); + + @SuppressWarnings("SameParameterValue") + public void addValue(String key, String value) { + values.put(key,value); + } + + @Override + public void initialize() throws UserConfigurationException { + + } + + @Override + public String getString(String key) { + return values.get(key); + } + + @Override + public String getString(String key, String defaultValue) { + if (values.containsKey(key)) { + return values.get(key); + } else { + return defaultValue; + } + } + + @Override + public int getInt(String key) { + return getInt(key, -1); + } + + @Override + public int getInt(String key, int defaultValue) { + if (values.containsKey(key)) { + return Integer.parseInt(values.get(key)); + } else { + return defaultValue; + } + } + + @Override + public boolean getBoolean(String key) { + return getBoolean(key, false); + } + + @Override + public boolean getBoolean(String key, boolean defaultValue) { + if (values.containsKey(key)) { + return Boolean.parseBoolean(values.get(key)); + } else { + return defaultValue; + } + } + + @Override + public List getList(String key) { + return null; + } + + @Override + public String getConcatenatedList(String key, String defaultValue) { + return null; + } + + @Override + public Collection getKeys() { + return values.keySet(); + } +}