You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ji...@apache.org on 2016/10/04 22:14:13 UTC
[1/3] incubator-geode git commit: GEODE-1570 - developer REST API
should be secured
Repository: incubator-geode
Updated Branches:
refs/heads/release/1.0.0-incubating d76eee424 -> 864fc08fa
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthentication.java
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthentication.java b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthentication.java
new file mode 100644
index 0000000..c4226f6
--- /dev/null
+++ b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthentication.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ *
+ */
+
+package org.apache.geode.rest.internal.web.security;
+
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.AuthorityUtils;
+
+class GeodeAuthentication extends UsernamePasswordAuthenticationToken {
+ /**
+ * This constructor should only be used by <code>AuthenticationManager</code> or <code>AuthenticationProvider</code>
+ * implementations that are satisfied with producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
+ * authentication token.
+ * @param principal
+ * @param credentials
+ */
+ public GeodeAuthentication(final Object principal,
+ final Object credentials) {
+ super(principal, credentials, AuthorityUtils.NO_AUTHORITIES);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthenticationProvider.java b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthenticationProvider.java
new file mode 100644
index 0000000..c482047
--- /dev/null
+++ b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthenticationProvider.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ *
+ */
+
+package org.apache.geode.rest.internal.web.security;
+
+import org.apache.shiro.subject.Subject;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.stereotype.Component;
+
+import org.apache.geode.internal.security.IntegratedSecurityService;
+import org.apache.geode.security.AuthenticationFailedException;
+
+
+@Component
+public class GeodeAuthenticationProvider implements AuthenticationProvider {
+
+ @Override
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+ String username = authentication.getName();
+ String password = authentication.getCredentials().toString();
+
+ try {
+ Subject subject = IntegratedSecurityService.getSecurityService().login(username, password);
+ if (subject != null) {
+ return new GeodeAuthentication(subject.getPrincipal(), authentication.getCredentials());
+ }
+ } catch (AuthenticationFailedException authFailedEx) {
+ throw new BadCredentialsException("Invalid username or password");
+ }
+ return authentication;
+ }
+
+ @Override
+ public boolean supports(Class<?> authentication) {
+ return authentication.equals(UsernamePasswordAuthenticationToken.class);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthority.java
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthority.java b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthority.java
new file mode 100644
index 0000000..fd21628
--- /dev/null
+++ b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/GeodeAuthority.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ */
+
+package org.apache.geode.rest.internal.web.security;
+
+import org.springframework.security.core.GrantedAuthority;
+
+public class GeodeAuthority implements GrantedAuthority {
+
+ private String authority;
+
+ GeodeAuthority(String authority) {
+ this.authority = authority;
+ }
+
+ /**
+ * If the <code>GrantedAuthority</code> can be represented as a <code>String</code> and that
+ * <code>String</code> is sufficient in precision to be relied upon for an access control decision by an {@link
+ * AccessDecisionManager} (or delegate), this method should return such a <code>String</code>.
+ * <p>
+ * If the <code>GrantedAuthority</code> cannot be expressed with sufficient precision as a <code>String</code>,
+ * <code>null</code> should be returned. Returning <code>null</code> will require an
+ * <code>AccessDecisionManager</code> (or delegate) to specifically support the <code>GrantedAuthority</code>
+ * implementation, so returning <code>null</code> should be avoided unless actually required.
+ * @return a representation of the granted authority (or <code>null</code> if the granted authority cannot be
+ * expressed as a <code>String</code> with sufficient precision).
+ */
+ @Override
+ public String getAuthority() {
+ return authority;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/RestSecurityConfiguration.java
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/RestSecurityConfiguration.java b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/RestSecurityConfiguration.java
new file mode 100644
index 0000000..f3b5c4d
--- /dev/null
+++ b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/security/RestSecurityConfiguration.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.geode.rest.internal.web.security;
+
+import org.apache.geode.internal.security.IntegratedSecurityService;
+import org.apache.geode.internal.security.SecurityService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+@ComponentScan("org.apache.geode.rest.internal.web")
+public class RestSecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ private SecurityService securityService = IntegratedSecurityService.getSecurityService();
+
+ @Autowired
+ private GeodeAuthenticationProvider authProvider;
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.authenticationProvider(authProvider);
+ }
+
+ @Bean
+ @Override
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return super.authenticationManagerBean();
+ }
+
+ protected void configure(HttpSecurity http) throws Exception {
+ http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ .and()
+ .authorizeRequests()
+ .antMatchers("/ping").permitAll()
+ .anyRequest().authenticated()
+ .and()
+ .formLogin()
+ .and()
+ .csrf().disable();
+
+ if(securityService.isIntegratedSecurity()) {
+ http.httpBasic();
+ }
+ else{
+ http
+ .authorizeRequests()
+ .anyRequest().permitAll();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/webapp/WEB-INF/geode-servlet.xml
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/webapp/WEB-INF/geode-servlet.xml b/geode-web-api/src/main/webapp/WEB-INF/geode-servlet.xml
index c24e74a..c75d975 100644
--- a/geode-web-api/src/main/webapp/WEB-INF/geode-servlet.xml
+++ b/geode-web-api/src/main/webapp/WEB-INF/geode-servlet.xml
@@ -30,20 +30,13 @@ limitations under the License.
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
">
<context:annotation-config />
- <context:component-scan base-package="org.apache.geode.rest.internal.web"/>
-
+
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
<mvc:message-converters register-defaults="false">
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
- <!-- bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" p:objectMapper-ref="objectMapper"/-->
<bean class="org.apache.geode.rest.internal.web.http.converter.CustomMappingJackson2HttpMessageConverter" p:objectMapper-ref="objectMapper"/>
- <!--bean class="org.gopivotal.app.http.converter.json.JsonToPdxInstanceHttpMessageConverter"/-->
- <!--bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/-->
- <!--bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter" p:marshaller-ref="jaxb2Marshaller" p:unmarshaller-ref="jaxb2Marshaller"/-->
- <!--bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter" p:marshaller-ref="xstreamMarshaller" p:unmarshaller-ref="xstreamMarshaller"/-->
- <!--bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/-->
</mvc:message-converters>
</mvc:annotation-driven>
@@ -62,7 +55,6 @@ limitations under the License.
</property>
</bean>
- <!-- bean id="objectMapper" class="org.apache.geode.rest.internal.web.config.CustomObjectMapper" factory-method="newObjectMapper"></bean-->
<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
p:failOnEmptyBeans="true"
p:indentOutput="true"
@@ -82,4 +74,5 @@ limitations under the License.
</property>
</bean>
+ <bean class="org.apache.geode.rest.internal.web.security.RestSecurityConfiguration" />
</beans>
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/webapp/WEB-INF/web.xml b/geode-web-api/src/main/webapp/WEB-INF/web.xml
index 956294a..f1f93c7 100644
--- a/geode-web-api/src/main/webapp/WEB-INF/web.xml
+++ b/geode-web-api/src/main/webapp/WEB-INF/web.xml
@@ -25,27 +25,17 @@ limitations under the License.
<description>
Web deployment descriptor declaring the developer REST API for GemFire.
</description>
-
- <!-- context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/META-INF/cache-config.xml</param-value>
- </context-param -->
-
+
<filter>
- <filter-name>httpPutFilter</filter-name>
- <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
- <async-supported>true</async-supported>
+ <filter-name>springSecurityFilterChain</filter-name>
+ <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
- <filter-name>httpPutFilter</filter-name>
+ <filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- <!-- listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener-->
-
<servlet>
<description>
The Spring DispatcherServlet (FrontController) handling all HTTP requests to the Developer REST API
@@ -61,5 +51,5 @@ limitations under the License.
<servlet-name>geode</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
-
+
</web-app>
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/gradle/dependency-versions.properties
----------------------------------------------------------------------
diff --git a/gradle/dependency-versions.properties b/gradle/dependency-versions.properties
index 0abe690..65fd2ee 100644
--- a/gradle/dependency-versions.properties
+++ b/gradle/dependency-versions.properties
@@ -88,13 +88,13 @@ powermock.version = 1.6.4
quartz.version = 2.2.1
scala.version = 2.10.0
selenium.version=2.53.1
-shiro.version=1.2.4
+shiro.version=1.3.0
slf4j-api.version = 1.7.7
snappy-java.version=0.4
spring-hateoas.version = 0.16.0.RELEASE
spring-shell.version = 1.1.0.RELEASE
spring-ldap-core.version = 1.3.2.RELEASE
-spring-security.version = 3.1.7.RELEASE
+spring-security.version = 3.2.7.RELEASE
spring-tx.version = 3.2.12.RELEASE
springframework.version = 4.2.4.RELEASE
stephenc-findbugs.version = 1.3.9-1
[3/3] incubator-geode git commit: GEODE-1570: make
GemFireVersion.properties available in the geode-core test source so that
other projects that depends on the geode-core-test can access it.
Posted by ji...@apache.org.
GEODE-1570: make GemFireVersion.properties available in the geode-core test source so that other projects that depends on the geode-core-test can access it.
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/864fc08f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/864fc08f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/864fc08f
Branch: refs/heads/release/1.0.0-incubating
Commit: 864fc08fa6ad44c054fb8e9d27fd90dd777ce598
Parents: 7b21520
Author: Jinmei Liao <ji...@pivotal.io>
Authored: Tue Oct 4 15:10:42 2016 -0700
Committer: Jinmei Liao <ji...@pivotal.io>
Committed: Tue Oct 4 15:10:42 2016 -0700
----------------------------------------------------------------------
geode-core/build.gradle | 3 +++
1 file changed, 3 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/864fc08f/geode-core/build.gradle
----------------------------------------------------------------------
diff --git a/geode-core/build.gradle b/geode-core/build.gradle
index b2e5a4e..3cbdfbe 100755
--- a/geode-core/build.gradle
+++ b/geode-core/build.gradle
@@ -131,6 +131,9 @@ sourceSets {
main {
output.dir(generatedResources, builtBy: 'createVersionPropertiesFile')
}
+ test {
+ output.dir(generatedResources, builtBy: 'createVersionPropertiesFile')
+ }
}
// Creates the version properties file and writes it to the classes dir
[2/3] incubator-geode git commit: GEODE-1570 - developer REST API
should be secured
Posted by ji...@apache.org.
GEODE-1570 - developer REST API should be secured
* Merged with develop after org.apache package rename
* Moved classes to internal.
* this closes #251
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/7b21520b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/7b21520b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/7b21520b
Branch: refs/heads/release/1.0.0-incubating
Commit: 7b21520b746413913b5ad5ed640e5c883eeccaab
Parents: d76eee4
Author: Kevin Duling <kd...@pivotal.io>
Authored: Wed Sep 21 08:50:46 2016 -0700
Committer: Jinmei Liao <ji...@pivotal.io>
Committed: Mon Oct 3 13:26:44 2016 -0700
----------------------------------------------------------------------
.../internal/web/RestSecurityDUnitTest.java | 247 +++++++++--
.../web/RestSecurityEndpointsDUnitTest.java | 422 +++++++++++++++++++
.../src/main/webapp/WEB-INF/spring-security.xml | 2 +-
geode-web-api/build.gradle | 6 +-
.../web/controllers/AbstractBaseController.java | 54 ++-
.../web/controllers/BaseControllerAdvice.java | 78 +++-
.../web/controllers/CommonCrudController.java | 87 ++--
.../controllers/FunctionAccessController.java | 36 +-
.../web/controllers/PdxBasedCrudController.java | 44 +-
.../web/controllers/QueryAccessController.java | 108 ++---
.../web/security/GeodeAuthentication.java | 37 ++
.../security/GeodeAuthenticationProvider.java | 56 +++
.../internal/web/security/GeodeAuthority.java | 47 +++
.../web/security/RestSecurityConfiguration.java | 76 ++++
.../src/main/webapp/WEB-INF/geode-servlet.xml | 11 +-
geode-web-api/src/main/webapp/WEB-INF/web.xml | 20 +-
gradle/dependency-versions.properties | 4 +-
17 files changed, 1116 insertions(+), 219 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-assembly/src/test/java/org/apache/geode/rest/internal/web/RestSecurityDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-assembly/src/test/java/org/apache/geode/rest/internal/web/RestSecurityDUnitTest.java b/geode-assembly/src/test/java/org/apache/geode/rest/internal/web/RestSecurityDUnitTest.java
index df146a6..a9d90ed 100644
--- a/geode-assembly/src/test/java/org/apache/geode/rest/internal/web/RestSecurityDUnitTest.java
+++ b/geode-assembly/src/test/java/org/apache/geode/rest/internal/web/RestSecurityDUnitTest.java
@@ -22,75 +22,236 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import org.apache.geode.internal.AvailablePortHelper;
+import org.apache.geode.security.AbstractSecureServerDUnitTest;
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.apache.geode.test.junit.categories.SecurityTest;
import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.AuthCache;
import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.client.BasicAuthCache;
+import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.junit.Test;
+import org.json.JSONTokener;
import org.junit.experimental.categories.Category;
-import org.apache.geode.internal.AvailablePortHelper;
-import org.apache.geode.security.AbstractSecureServerDUnitTest;
-import org.apache.geode.test.junit.categories.DistributedTest;
-import org.apache.geode.test.junit.categories.SecurityTest;
-@Category({ DistributedTest.class, SecurityTest.class})
+@Category({ DistributedTest.class, SecurityTest.class })
public class RestSecurityDUnitTest extends AbstractSecureServerDUnitTest {
- private String endPoint = null;
- public RestSecurityDUnitTest(){
+
+ public final static String PROTOCOL = "http";
+ public final static String HOSTNAME = "localhost";
+ public final static String CONTEXT = "/geode/v1";
+
+ private final String endPoint;
+ private final URL url;
+
+ public RestSecurityDUnitTest() throws MalformedURLException {
int[] ports = AvailablePortHelper.getRandomAvailableTCPPorts(2);
this.jmxPort = ports[0];
this.restPort = ports[1];
- endPoint = "http://localhost:"+restPort+"/gemfire-api/v1";
+ endPoint = PROTOCOL + "://" + HOSTNAME + ":" + restPort + CONTEXT;
+ url = new URL(endPoint);
+ }
+
+ protected HttpResponse doHEAD(String query, String username, String password) throws MalformedURLException {
+ HttpHost targetHost = new HttpHost(url.getHost(), url.getPort(), url.getProtocol());
+ HttpClientContext clientContext = HttpClientContext.create();
+ CredentialsProvider credsProvider = new BasicCredentialsProvider();
+ credsProvider.setCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()), new UsernamePasswordCredentials(username, password));
+ CloseableHttpClient httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+ AuthCache authCache = new BasicAuthCache();
+ BasicScheme basicAuth = new BasicScheme();
+ authCache.put(targetHost, basicAuth);
+ clientContext.setCredentialsProvider(credsProvider);
+ clientContext.setAuthCache(authCache);
+
+ HttpHead httpHead = new HttpHead(CONTEXT + query);
+ try {
+ return httpclient.execute(targetHost, httpHead, clientContext);
+ } catch (ClientProtocolException e) {
+ e.printStackTrace();
+ fail("Rest HEAD should not have thrown ClientProtocolException!");
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail("Rest HEAD Request should not have thrown IOException!");
+ }
+ return null;
+ }
+
+ protected HttpResponse doGet(String query, String username, String password) throws MalformedURLException {
+ HttpHost targetHost = new HttpHost(url.getHost(), url.getPort(), url.getProtocol());
+ CloseableHttpClient httpclient = HttpClients.custom().build();
+ HttpClientContext clientContext = HttpClientContext.create();
+// // if username or password are null or empty, do not put in authentication
+// if (!(username == null
+// || password == null
+// || !username.isEmpty()
+// || !password.isEmpty())) {
+ CredentialsProvider credsProvider = new BasicCredentialsProvider();
+ credsProvider.setCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()), new UsernamePasswordCredentials(username, password));
+ httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+ AuthCache authCache = new BasicAuthCache();
+ BasicScheme basicAuth = new BasicScheme();
+ authCache.put(targetHost, basicAuth);
+ clientContext.setCredentialsProvider(credsProvider);
+ clientContext.setAuthCache(authCache);
+// }
+
+ HttpGet getRequest = new HttpGet(CONTEXT + query);
+ try {
+ return httpclient.execute(targetHost, getRequest, clientContext);
+ } catch (ClientProtocolException e) {
+ e.printStackTrace();
+ fail("Rest GET should not have thrown ClientProtocolException!");
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail("Rest GET Request should not have thrown IOException!");
+ }
+ return null;
}
- @Test
- public void test(){
- client1.invoke(()->{
- JSONArray response = doGet("/servers");
- assertEquals(response.length(), 1);
- assertEquals(response.get(0), "http://localhost:"+this.restPort);
- });
+
+ protected HttpResponse doDelete(String query, String username, String password) throws MalformedURLException {
+ HttpHost targetHost = new HttpHost(url.getHost(), url.getPort(), url.getProtocol());
+ CredentialsProvider credsProvider = new BasicCredentialsProvider();
+ credsProvider.setCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()), new UsernamePasswordCredentials(username, password));
+ CloseableHttpClient httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+ AuthCache authCache = new BasicAuthCache();
+ BasicScheme basicAuth = new BasicScheme();
+ authCache.put(targetHost, basicAuth);
+
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCredentialsProvider(credsProvider);
+ clientContext.setAuthCache(authCache);
+
+ HttpDelete httpDelete = new HttpDelete(CONTEXT + query);
+ try {
+ return httpclient.execute(targetHost, httpDelete, clientContext);
+ } catch (ClientProtocolException e) {
+ e.printStackTrace();
+ fail("Rest DELETE Request should not have thrown ClientProtocolException!");
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail("Rest DELETE Request should not have thrown IOException!");
+ }
+ return null;
}
+ protected HttpResponse doPost(String query, String username, String password, String body) throws MalformedURLException {
+ HttpHost targetHost = new HttpHost(url.getHost(), url.getPort(), url.getProtocol());
+ CredentialsProvider credsProvider = new BasicCredentialsProvider();
+ credsProvider.setCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()), new UsernamePasswordCredentials(username, password));
+ CloseableHttpClient httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+ AuthCache authCache = new BasicAuthCache();
+ BasicScheme basicAuth = new BasicScheme();
+ authCache.put(targetHost, basicAuth);
- private JSONArray doGet(String uri) {
- HttpGet get = new HttpGet(endPoint + uri);
- get.addHeader("Content-Type", "application/json");
- get.addHeader("Accept", "application/json");
- CloseableHttpClient httpclient = HttpClients.createDefault();
- CloseableHttpResponse response;
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCredentialsProvider(credsProvider);
+ clientContext.setAuthCache(authCache);
+ HttpPost httpPost = new HttpPost(CONTEXT + query);
+ httpPost.addHeader("content-type", "application/json");
+ httpPost.setEntity(new StringEntity(body, StandardCharsets.UTF_8));
try {
- response = httpclient.execute(get);
- HttpEntity entity = response.getEntity();
- InputStream content = entity.getContent();
- BufferedReader reader = new BufferedReader(new InputStreamReader(
- content));
- String line;
- StringBuffer str = new StringBuffer();
- while ((line = reader.readLine()) != null) {
- str.append(line);
- }
-
- //validate the satus code
- assertEquals(response.getStatusLine().getStatusCode(), 200);
- return new JSONArray(str.toString());
+ return httpclient.execute(targetHost, httpPost, clientContext);
} catch (ClientProtocolException e) {
e.printStackTrace();
- fail(" Rest Request should not have thrown ClientProtocolException!");
+ fail("Rest POST Request should not have thrown ClientProtocolException!");
} catch (IOException e) {
e.printStackTrace();
- fail(" Rest Request should not have thrown IOException!");
- } catch (JSONException e) {
+ fail("Rest POST Request should not have thrown IOException!");
+ }
+ return null;
+ }
+ protected HttpResponse doPut(String query, String username, String password, String body) throws MalformedURLException {
+ HttpHost targetHost = new HttpHost(url.getHost(), url.getPort(), url.getProtocol());
+ CredentialsProvider credsProvider = new BasicCredentialsProvider();
+ credsProvider.setCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()), new UsernamePasswordCredentials(username, password));
+ CloseableHttpClient httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+ AuthCache authCache = new BasicAuthCache();
+ BasicScheme basicAuth = new BasicScheme();
+ authCache.put(targetHost, basicAuth);
+
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCredentialsProvider(credsProvider);
+ clientContext.setAuthCache(authCache);
+
+ HttpPut httpPut = new HttpPut(CONTEXT + query);
+ httpPut.addHeader("content-type", "application/json");
+ httpPut.setEntity(new StringEntity(body, StandardCharsets.UTF_8));
+ try {
+ return httpclient.execute(targetHost, httpPut, clientContext);
+ } catch (ClientProtocolException e) {
e.printStackTrace();
- fail(" Rest Request should not have thrown JSONException!");
+ fail("Rest PUT Request should not have thrown ClientProtocolException!");
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail("Rest PUT Request should not have thrown IOException!");
}
return null;
}
+ /**
+ * Check the HTTP status of the response and return if it's within the OK range
+ * @param response The HttpResponse message received from the server
+ *
+ * @return true if the status code is a 2XX-type code (200-299), otherwise false
+ */
+ protected boolean isOK(HttpResponse response) {
+ int returnCode = response.getStatusLine().getStatusCode();
+ return (returnCode < 300 && returnCode >= 200);
+ }
+
+ /**
+ * Check the HTTP status of the response and return true if a 401
+ * @param response The HttpResponse message received from the server
+ *
+ * @return true if the status code is 401, otherwise false
+ */
+ protected boolean isUnauthorized(HttpResponse response) {
+ int returnCode = response.getStatusLine().getStatusCode();
+ return returnCode == 401;
+ }
+
+ /**
+ * Retrieve the status code of the HttpResponse
+ * @param response The HttpResponse message received from the server
+ *
+ * @return a numeric value
+ */
+ protected int getCode(HttpResponse response) {
+ return response.getStatusLine().getStatusCode();
+ }
+
+ protected JSONTokener getResponseBody(HttpResponse response) throws IOException {
+ HttpEntity entity = response.getEntity();
+ InputStream content = entity.getContent();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ content));
+ String line;
+ StringBuilder str = new StringBuilder();
+ while ((line = reader.readLine()) != null) {
+ str.append(line);
+ }
+ return new JSONTokener(str.toString());
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-assembly/src/test/java/org/apache/geode/rest/internal/web/RestSecurityEndpointsDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-assembly/src/test/java/org/apache/geode/rest/internal/web/RestSecurityEndpointsDUnitTest.java b/geode-assembly/src/test/java/org/apache/geode/rest/internal/web/RestSecurityEndpointsDUnitTest.java
new file mode 100644
index 0000000..149a905
--- /dev/null
+++ b/geode-assembly/src/test/java/org/apache/geode/rest/internal/web/RestSecurityEndpointsDUnitTest.java
@@ -0,0 +1,422 @@
+/*
+ * 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.
+ */
+package org.apache.geode.rest.internal.web;
+
+import static org.junit.Assert.*;
+
+import java.net.MalformedURLException;
+
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.apache.geode.test.junit.categories.SecurityTest;
+import org.apache.http.HttpResponse;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@SuppressWarnings("serial")
+@Category({ DistributedTest.class, SecurityTest.class })
+public class RestSecurityEndpointsDUnitTest extends RestSecurityDUnitTest {
+
+ Logger logger = LoggerFactory.getLogger(RestSecurityEndpointsDUnitTest.class);
+
+ public RestSecurityEndpointsDUnitTest() throws MalformedURLException {
+ super();
+ }
+
+ @Test
+ public void testFunctions() {
+ client1.invoke(() -> {
+ String json = "{\"@type\":\"double\",\"@value\":210}";
+
+ HttpResponse response = doGet("/functions", "unknown-user", "1234567");
+ assertEquals(401, getCode(response));
+ response = doGet("/functions", "stranger", "1234567");
+ assertEquals(403, getCode(response));
+ response = doGet("/functions", "dataReader", "1234567");
+ assertTrue(isOK(response));
+
+ response = doPost("/functions/AddFreeItemsToOrder", "unknown-user", "1234567", json);
+ assertEquals(401, getCode(response));
+ response = doPost("/functions/AddFreeItemsToOrder", "dataReader", "1234567", json);
+ assertEquals(403, getCode(response));
+ response = doPost("/functions/AddFreeItemsToOrder?onRegion=" + REGION_NAME, "dataWriter", "1234567", json);
+ // because we're only testing the security of the endpoint, not the endpoint functionality, a 500 is acceptable
+ assertEquals(500, getCode(response));
+ });
+ }
+
+ @Test
+ public void testQueries() {
+ client1.invoke(() -> {
+ HttpResponse response = doGet("/queries", "unknown-user", "1234567");
+ assertEquals(401, getCode(response));
+ response = doGet("/queries", "stranger", "1234567");
+ assertEquals(403, getCode(response));
+ response = doGet("/queries", "dataReader", "1234567");
+ assertEquals(200, getCode(response));
+ });
+ }
+
+ @Test
+ public void testAdhocQuery() {
+ client1.invoke(() -> {
+ HttpResponse response = doGet("/queries/adhoc?q=", "unknown-user", "1234567");
+ assertEquals(401, getCode(response));
+ response = doGet("/queries/adhoc?q=", "stranger", "1234567");
+ assertEquals(403, getCode(response));
+ response = doGet("/queries/adhoc?q=", "dataReader", "1234567");
+ // because we're only testing the security of the endpoint, not the endpoint functionality, a 500 is acceptable
+ assertEquals(500, getCode(response));
+ });
+ }
+
+ @Test
+ public void testPostQuery() {
+ client1.invoke(() -> {
+ HttpResponse response = doPost("/queries?id=0&q=", "unknown-user", "1234567", "");
+ assertEquals(401, getCode(response));
+ response = doPost("/queries?id=0&q=", "stranger", "1234567", "");
+ assertEquals(403, getCode(response));
+ response = doPost("/queries?id=0&q=", "dataWriter", "1234567", "");
+ // because we're only testing the security of the endpoint, not the endpoint functionality, a 500 is acceptable
+ assertEquals(500, getCode(response));
+ });
+ }
+
+ @Test
+ public void testPostQuery2() {
+ client1.invoke(() -> {
+ HttpResponse response = doPost("/queries/id", "unknown-user", "1234567", "{\"id\" : \"foo\"}");
+ assertEquals(401, getCode(response));
+ response = doPost("/queries/id", "stranger", "1234567", "{\"id\" : \"foo\"}");
+ assertEquals(403, getCode(response));
+ response = doPost("/queries/id", "dataWriter", "1234567", "{\"id\" : \"foo\"}");
+ // because we're only testing the security of the endpoint, not the endpoint functionality, a 500 is acceptable
+ assertEquals(500, getCode(response));
+ });
+ }
+
+ @Test
+ public void testPutQuery() {
+ client1.invoke(() -> {
+ HttpResponse response = doPut("/queries/id", "unknown-user", "1234567", "{\"id\" : \"foo\"}");
+ assertEquals(401, getCode(response));
+ response = doPut("/queries/id", "stranger", "1234567", "{\"id\" : \"foo\"}");
+ assertEquals(403, getCode(response));
+ response = doPut("/queries/id", "dataWriter", "1234567", "{\"id\" : \"foo\"}");
+ // We should get a 404 because we're trying to update a query that doesn't exist
+ assertEquals(404, getCode(response));
+ });
+ }
+
+ @Test
+ public void testDeleteQuery() {
+ client1.invoke(() -> {
+ HttpResponse response = doDelete("/queries/id", "unknown-user", "1234567");
+ assertEquals(401, getCode(response));
+ response = doDelete("/queries/id", "stranger", "1234567");
+ assertEquals(403, getCode(response));
+ response = doDelete("/queries/id", "dataWriter", "1234567");
+ // We should get a 404 because we're trying to delete a query that doesn't exist
+ assertEquals(404, getCode(response));
+ });
+ }
+
+ @Test
+ public void testServers() {
+ client1.invoke(() -> {
+ HttpResponse response = doGet("/servers", "unknown-user", "1234567");
+ assertEquals(401, getCode(response));
+ response = doGet("/servers", "stranger", "1234567");
+ assertEquals(403, getCode(response));
+ response = doGet("/servers", "super-user", "1234567");
+ assertTrue(isOK(response));
+ });
+ }
+
+ /**
+ * This test should always return an OK, whether the user is known or unknown. A phishing script should not be
+ * able to determine whether a user/password combination is good
+ */
+ @Test
+ public void testPing() {
+ client1.invoke(() -> {
+ HttpResponse response = doHEAD("/ping", "stranger", "1234567");
+ assertTrue(isOK(response));
+ response = doGet("/ping", "stranger", "1234567");
+ assertTrue(isOK(response));
+
+ response = doHEAD("/ping", "super-user", "1234567");
+ assertTrue(isOK(response));
+ response = doGet("/ping", "super-user", "1234567");
+ assertTrue(isOK(response));
+
+ // TODO - invalid username/password should still respond, but doesn't
+ // response = doHEAD("/ping", "unknown-user", "badpassword");
+ // assertTrue(isOK(response));
+ // response = doGet("/ping", "unknown-user", "badpassword");
+ // assertTrue(isOK(response));
+
+ // TODO - credentials are currently required and shouldn't be for this endpoint
+ // response = doHEAD("/ping", null, null);
+ // assertTrue(isOK(response));
+ // response = doGet("/ping", null, null);
+ // assertTrue(isOK(response));
+ });
+ }
+
+ /**
+ * Test permissions on retrieving a list of regions.
+ */
+ @Test
+ public void getRegions() {
+ client1.invoke(() -> {
+ HttpResponse response = doGet("", "dataReader", "1234567");
+ assertEquals("A '200 - OK' was expected", 200, getCode(response));
+
+ assertTrue(isOK(response));
+ JSONObject jsonObject = new JSONObject(getResponseBody(response));
+ JSONArray regions = jsonObject.getJSONArray("regions");
+ assertNotNull(regions);
+ assertTrue(regions.length() > 0);
+ JSONObject region = regions.getJSONObject(0);
+ assertEquals("AuthRegion", region.get("name"));
+ assertEquals("REPLICATE", region.get("type"));
+ });
+
+ // List regions with an unknown user - 401
+ client1.invoke(() -> {
+ HttpResponse response = doGet("", "unknown-user", "badpassword");
+ assertEquals(401, getCode(response));
+ });
+
+ // list regions with insufficent rights - 403
+ client1.invoke(() -> {
+ HttpResponse response = doGet("", "authRegionReader", "1234567");
+ assertEquals(403, getCode(response));
+ });
+ }
+
+ /**
+ * Test permissions on getting a region
+ */
+ @Test
+ public void getRegion() {
+ // Test an unknown user - 401 error
+ client1.invoke(() -> {
+ HttpResponse response = doGet("/" + REGION_NAME, "unknown-user", "1234567");
+ assertEquals(401, getCode(response));
+ });
+
+ // Test a user with insufficient rights - 403
+ client1.invoke(() -> {
+ HttpResponse response = doGet("/" + REGION_NAME, "stranger", "1234567");
+ assertEquals(403, getCode(response));
+ });
+
+ // Test an authorized user - 200
+ client1.invoke(() -> {
+ HttpResponse response = doGet("/" + REGION_NAME, "super-user", "1234567");
+ assertTrue(isOK(response));
+ });
+ }
+
+ /**
+ * Test permissions on HEAD region
+ */
+ @Test
+ public void headRegion() {
+ // Test an unknown user - 401 error
+ client1.invoke(() -> {
+ HttpResponse response = doHEAD("/" + REGION_NAME, "unknown-user", "1234567");
+ assertEquals(401, getCode(response));
+ });
+
+ // Test a user with insufficient rights - 403
+ client1.invoke(() -> {
+ HttpResponse response = doHEAD("/" + REGION_NAME, "stranger", "1234567");
+ assertEquals(403, getCode(response));
+ });
+
+ // Test an authorized user - 200
+ client1.invoke(() -> {
+ HttpResponse response = doHEAD("/" + REGION_NAME, "super-user", "1234567");
+ assertTrue(isOK(response));
+ });
+ }
+
+ /**
+ * Test permissions on deleting a region
+ */
+ @Test
+ public void deleteRegion() {
+ // Test an unknown user - 401 error
+ client1.invoke(() -> {
+ HttpResponse response = doDelete("/" + REGION_NAME, "unknown-user", "1234567");
+ assertEquals(401, getCode(response));
+ });
+
+ // Test a user with insufficient rights - 403
+ client1.invoke(() -> {
+ HttpResponse response = doDelete("/" + REGION_NAME, "dataReader", "1234567");
+ assertEquals(403, getCode(response));
+ });
+
+ // Test an authorized user - 200
+ client1.invoke(() -> {
+ HttpResponse response = doDelete("/" + REGION_NAME, "super-user", "1234567");
+ assertTrue(isOK(response));
+ });
+ }
+
+ /**
+ * Test permissions on getting a region's keys
+ */
+ @Test
+ public void getRegionKeys() {
+ // Test an authorized user
+ client1.invoke(() -> {
+ HttpResponse response = doGet("/" + REGION_NAME + "/keys", "super-user", "1234567");
+ assertTrue(isOK(response));
+ });
+ // Test an unauthorized user
+ client1.invoke(() -> {
+ HttpResponse response = doGet("/" + REGION_NAME + "/keys", "dataWriter", "1234567");
+ assertEquals(403, getCode(response));
+ });
+ }
+
+ /**
+ * Test permissions on retrieving a key from a region
+ */
+ @Test
+ public void getRegionKey() {
+ // Test an authorized user
+ client1.invoke(() -> {
+ HttpResponse response = doGet("/" + REGION_NAME + "/key1", "key1User", "1234567");
+ assertTrue(isOK(response));
+ });
+ // Test an unauthorized user
+ client1.invoke(() -> {
+ HttpResponse response = doGet("/" + REGION_NAME + "/key1", "dataWriter", "1234567");
+ assertEquals(403, getCode(response));
+ });
+ }
+
+ /**
+ * Test permissions on deleting a region's key(s)
+ */
+ @Test
+ public void deleteRegionKey() {
+ // Test an unknown user - 401 error
+ client1.invoke(() -> {
+ HttpResponse response = doDelete("/" + REGION_NAME + "/key1", "unknown-user", "1234567");
+ assertEquals(401, getCode(response));
+ });
+
+ // Test a user with insufficient rights - 403
+ client1.invoke(() -> {
+ HttpResponse response = doDelete("/" + REGION_NAME + "/key1", "dataReader", "1234567");
+ assertEquals(403, getCode(response));
+ });
+
+ // Test an authorized user - 200
+ client1.invoke(() -> {
+ HttpResponse response = doDelete("/" + REGION_NAME + "/key1", "key1User", "1234567");
+ assertTrue(isOK(response));
+ });
+ }
+
+ /**
+ * Test permissions on deleting a region's key(s)
+ */
+ @Test
+ public void postRegionKey() {
+ // Test an unknown user - 401 error
+ client1.invoke(() -> {
+ HttpResponse response = doPost("/" + REGION_NAME + "?key9", "unknown", "1234567", "{ \"key9\" : \"foo\" }");
+ assertEquals(401, getCode(response));
+ });
+
+ // Test a user with insufficient rights - 403
+ client1.invoke(() -> {
+ HttpResponse response = doPost("/" + REGION_NAME + "?key9", "dataReader", "1234567", "{ \"key9\" : \"foo\" }");
+ assertEquals(403, getCode(response));
+ });
+
+ // Test an authorized user - 200
+ client1.invoke(() -> {
+ HttpResponse response = doPost("/" + REGION_NAME + "?key9", "dataWriter", "1234567", "{ \"key9\" : \"foo\" }");
+ assertEquals(201, getCode(response));
+ assertTrue(isOK(response));
+ });
+ }
+
+ /**
+ * Test permissions on deleting a region's key(s)
+ */
+ @Test
+ public void putRegionKey() {
+
+ String json = "{\"@type\":\"com.gemstone.gemfire.web.rest.domain.Order\",\"purchaseOrderNo\":1121,\"customerId\":1012,\"description\":\"Order for XYZ Corp\",\"orderDate\":\"02/10/2014\",\"deliveryDate\":\"02/20/2014\",\"contact\":\"Jelly Bean\",\"email\":\"jelly.bean@example.com\",\"phone\":\"01-2048096\",\"items\":[{\"itemNo\":1,\"description\":\"Product-100\",\"quantity\":12,\"unitPrice\":5,\"totalPrice\":60}],\"totalPrice\":225}";
+ String casJSON = "{\"@old\":{\"@type\":\"com.gemstone.gemfire.web.rest.domain.Order\",\"purchaseOrderNo\":1121,\"customerId\":1012,\"description\":\"Order for XYZ Corp\",\"orderDate\":\"02/10/2014\",\"deliveryDate\":\"02/20/2014\",\"contact\":\"Jelly Bean\",\"email\":\"jelly.bean@example.com\",\"phone\":\"01-2048096\",\"items\":[{\"itemNo\":1,\"description\":\"Product-100\",\"quantity\":12,\"unitPrice\":5,\"totalPrice\":60}],\"totalPrice\":225},\"@new \":{\"@type\":\"com.gemstone.gemfire.web.rest.domain.Order\",\"purchaseOrderNo\":1121,\"customerId\":1013,\"description\":\"Order for New Corp\",\"orderDate\":\"02/10/2014\",\"deliveryDate\":\"02/25/2014\",\"contact\":\"Vanilla Bean\",\"email\":\"vanillabean@example.com\",\"phone\":\"01-2048096\",\"items\":[{\"itemNo\":12345,\"description\":\"part 123\",\"quantity\":12,\"unitPrice\":29.99,\"totalPrice\":149.95}],\"totalPrice\":149.95}}";
+ // Test an unknown user - 401 error
+ client1.invoke(() -> {
+ HttpResponse response = doPut("/" + REGION_NAME + "/key1?op=PUT", "unknown-user", "1234567", "{ \"key9\" : \"foo\" }");
+ assertEquals(401, getCode(response));
+ });
+
+ client1.invoke(() -> {
+ HttpResponse response = doPut("/" + REGION_NAME + "/key1?op=CAS", "unknown-user", "1234567", "{ \"key9\" : \"foo\" }");
+ assertEquals(401, getCode(response));
+ });
+
+ client1.invoke(() -> {
+ HttpResponse response = doPut("/" + REGION_NAME + "/key1?op=REPLACE", "unknown-user", "1234567", "{ \"@old\" : \"value1\", \"@new\" : \"CASvalue\" }");
+ assertEquals(401, getCode(response));
+ });
+
+ // Test a user with insufficient rights - 403
+ client1.invoke(() -> {
+ HttpResponse response = doPut("/" + REGION_NAME + "/key1?op=PUT", "dataReader", "1234567", "{ \"key1\" : \"foo\" }");
+ assertEquals(403, getCode(response));
+ });
+ client1.invoke(() -> {
+ HttpResponse response = doPut("/" + REGION_NAME + "/key1?op=REPLACE", "dataReader", "1234567", "{ \"key1\" : \"foo\" }");
+ assertEquals(403, getCode(response));
+ });
+ client1.invoke(() -> {
+ HttpResponse response = doPut("/" + REGION_NAME + "/key1?op=CAS", "dataReader", "1234567", casJSON);
+ assertEquals(403, getCode(response));
+ });
+
+ // Test an authorized user - 200
+ client1.invoke(() -> {
+ HttpResponse response = doPut("/" + REGION_NAME + "/key1?op=PUT", "key1User", "1234567", "{ \"key1\" : \"foo\" }");
+ assertEquals(200, getCode(response));
+ assertTrue(isOK(response));
+ });
+ client1.invoke(() -> {
+ HttpResponse response = doPut("/" + REGION_NAME + "/key1?op=REPLACE", "key1User", "1234567", json);
+ assertEquals(200, getCode(response));
+ assertTrue(isOK(response));
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-pulse/src/main/webapp/WEB-INF/spring-security.xml
----------------------------------------------------------------------
diff --git a/geode-pulse/src/main/webapp/WEB-INF/spring-security.xml b/geode-pulse/src/main/webapp/WEB-INF/spring-security.xml
index 3756df7..924dd50 100644
--- a/geode-pulse/src/main/webapp/WEB-INF/spring-security.xml
+++ b/geode-pulse/src/main/webapp/WEB-INF/spring-security.xml
@@ -22,7 +22,7 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
- http://www.springframework.org/schema/security/spring-security-3.1.xsd
+ http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/build.gradle
----------------------------------------------------------------------
diff --git a/geode-web-api/build.gradle b/geode-web-api/build.gradle
index 9e93bb9..3ea652b 100755
--- a/geode-web-api/build.gradle
+++ b/geode-web-api/build.gradle
@@ -29,7 +29,7 @@ dependencies {
compile 'com.fasterxml.jackson.core:jackson-databind:' + project.'jackson.version'
compile 'com.fasterxml.jackson.module:jackson-module-scala_2.10:' + project.'jackson-module-scala_2.10.version'
compile 'com.google.guava:guava:' + project.'guava.version'
- compile ('com.mangofactory:swagger-springmvc:' + project.'swagger-springmvc.version') {
+ compile ('com.mangofactory:swagger-springmvc:' + project.'swagger-springmvc.version') {
exclude module: 'aopalliance'
exclude module: 'asm'
exclude module: 'cglib'
@@ -53,6 +53,10 @@ dependencies {
compile 'org.json4s:json4s-ast_2.10:' + project.'json4s.version'
compile 'org.scala-lang:scala-library:' + project.'scala.version'
compile 'org.scala-lang:scala-reflect:' + project.'scala.version'
+ compile 'org.springframework:spring-beans:' + project.'springframework.version'
+ compile 'org.springframework.security:spring-security-core:' + project.'spring-security.version'
+ compile 'org.springframework.security:spring-security-web:' + project.'spring-security.version'
+ compile 'org.springframework.security:spring-security-config:' + project.'spring-security.version'
compile ('org.springframework.hateoas:spring-hateoas:' + project.'spring-hateoas.version') {
exclude module: 'aopalliance'
exclude module: 'commons-logging'
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/AbstractBaseController.java
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/AbstractBaseController.java b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/AbstractBaseController.java
index e94998b..ee5d714 100644
--- a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/AbstractBaseController.java
+++ b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/AbstractBaseController.java
@@ -35,17 +35,6 @@ import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.PostConstruct;
-import org.apache.logging.log4j.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.util.Assert;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
-
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
@@ -60,13 +49,13 @@ import org.apache.geode.cache.Region;
import org.apache.geode.cache.TimeoutException;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.distributed.LeaseExpiredException;
import org.apache.geode.distributed.internal.DistributionManager;
-import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
-import org.apache.geode.i18n.LogWriterI18n;
import org.apache.geode.internal.cache.GemFireCacheImpl;
-import org.apache.geode.internal.i18n.LocalizedStrings;
import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.security.IntegratedSecurityService;
+import org.apache.geode.internal.security.SecurityService;
import org.apache.geode.pdx.JSONFormatter;
import org.apache.geode.pdx.JSONFormatterException;
import org.apache.geode.pdx.PdxInstance;
@@ -82,10 +71,21 @@ import org.apache.geode.rest.internal.web.util.IdentifiableUtils;
import org.apache.geode.rest.internal.web.util.JSONUtils;
import org.apache.geode.rest.internal.web.util.NumberUtils;
import org.apache.geode.rest.internal.web.util.ValidationUtils;
+import org.apache.logging.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+
/**
* AbstractBaseController class contains common functionalities required for other controllers.
@@ -104,6 +104,7 @@ public abstract class AbstractBaseController {
protected static final String UTF_8 = "UTF-8";
protected static final String DEFAULT_ENCODING = UTF_8;
private static final AtomicLong ID_SEQUENCE = new AtomicLong(0l);
+ protected SecurityService securityService = IntegratedSecurityService.getSecurityService();
//private Cache cache = GemFireCacheImpl.getExisting(null);
@@ -199,7 +200,7 @@ public abstract class AbstractBaseController {
final HttpHeaders headers = new HttpHeaders();
headers.setLocation(toUri("queries", queryId));
- return new ResponseEntity<>(queryResultAsJson, headers, HttpStatus.OK);
+ return new ResponseEntity<String>(queryResultAsJson, headers, HttpStatus.OK);
}else {
throw new GemfireRestException("Server has encountered error while generating query result into restful format(JSON)!");
}
@@ -252,7 +253,7 @@ public abstract class AbstractBaseController {
throw new GemfireRestException(String.format("Resource (%1$s) configuration does not allow null keys or values!", regionNamePath), npe);
}catch(IllegalArgumentException iae){
throw new GemfireRestException(String.format("Resource (%1$s) configuration prevents specified data from being stored in it!", regionNamePath), iae);
- }catch(org.apache.geode.distributed.LeaseExpiredException lee){
+ }catch(LeaseExpiredException lee){
throw new GemfireRestException("Server has encountered error while processing this request!", lee);
}catch(TimeoutException toe){
throw new GemfireRestException("Server has encountered timeout error while processing this request!", toe);
@@ -278,7 +279,7 @@ public abstract class AbstractBaseController {
throw new GemfireRestException(String.format("Resource (%1$s) configuration does not allow null keys or values!", regionNamePath), npe);
}catch(IllegalArgumentException iae){
throw new GemfireRestException(String.format("Resource (%1$s) configuration prevents specified data from being stored in it!", regionNamePath), iae);
- }catch(org.apache.geode.distributed.LeaseExpiredException lee){
+ }catch(LeaseExpiredException lee){
throw new GemfireRestException("Server has encountered error while processing this request!", lee);
}catch(TimeoutException toe){
throw new GemfireRestException("Server has encountered timeout error while processing this request!", toe);
@@ -305,7 +306,7 @@ public abstract class AbstractBaseController {
throw new GemfireRestException(String.format("Resource (%1$s) configuration does not allow null keys or values!", regionNamePath), npe);
}catch(IllegalArgumentException iae){
throw new GemfireRestException(String.format("Resource (%1$s) configuration prevents specified data from being stored in it!", regionNamePath), iae);
- }catch(org.apache.geode.distributed.LeaseExpiredException lee){
+ }catch(LeaseExpiredException lee){
throw new GemfireRestException("Server has encountered error while processing this request!", lee);
}catch(TimeoutException toe){
throw new GemfireRestException("Server has encountered timeout error while processing this request!", toe);
@@ -325,7 +326,7 @@ public abstract class AbstractBaseController {
throw new GemfireRestException(String.format("Resource (%1$s) configuration does not allow null keys or values!", regionNamePath), npe);
} catch (ClassCastException cce) {
throw new GemfireRestException(String.format("Resource (%1$s) configuration does not allow to store specified key or value type in this region!", regionNamePath), cce);
- } catch (org.apache.geode.distributed.LeaseExpiredException lee) {
+ } catch (LeaseExpiredException lee) {
throw new GemfireRestException("Server has encountered error while processing this request!", lee);
} catch (TimeoutException toe) {
throw new GemfireRestException("Server has encountered timeout error while processing this request!", toe);
@@ -368,7 +369,7 @@ public abstract class AbstractBaseController {
throw new GemfireRestException("NULL query ID or query string is not supported!", npe);
} catch(IllegalArgumentException iae) {
throw new GemfireRestException("Server has not allowed to perform the requested operation!", iae);
- } catch(org.apache.geode.distributed.LeaseExpiredException lee) {
+ } catch(LeaseExpiredException lee) {
throw new GemfireRestException("Server has encountered error while processing this request!", lee);
} catch(TimeoutException te) {
throw new GemfireRestException("Server has encountered timeout error while processing this request!", te);
@@ -382,7 +383,7 @@ public abstract class AbstractBaseController {
throw new GemfireRestException("NULL query ID or query string is not supported!", npe);
} catch (ClassCastException cce) {
throw new GemfireRestException("specified queryId or query string is not supported!", cce);
- } catch (org.apache.geode.distributed.LeaseExpiredException lee) {
+ } catch (LeaseExpiredException lee) {
throw new GemfireRestException("Server has encountered error while processing this request!", lee);
} catch (TimeoutException toe) {
throw new GemfireRestException("Server has encountered timeout error while processing this request!", toe);
@@ -403,7 +404,7 @@ public abstract class AbstractBaseController {
throw new GemfireRestException("NULL query ID or query string is not supported!", npe);
} catch(IllegalArgumentException iae){
throw new GemfireRestException("Configuration does not allow to perform the requested operation!", iae);
- } catch(org.apache.geode.distributed.LeaseExpiredException lee){
+ } catch(LeaseExpiredException lee){
throw new GemfireRestException("Server has encountered error while processing this request!", lee);
} catch(TimeoutException toe){
throw new GemfireRestException("Server has encountered timeout error while processing this request!", toe);
@@ -451,7 +452,7 @@ public abstract class AbstractBaseController {
throw new GemfireRestException(String.format("Resource (%1$s) configuration does not allow null keys or values!", regionNamePath), npe);
}catch(IllegalArgumentException iae){
throw new GemfireRestException(String.format("Resource (%1$s) configuration prevents specified data from being stored in it!", regionNamePath), iae);
- }catch(org.apache.geode.distributed.LeaseExpiredException lee){
+ }catch(LeaseExpiredException lee){
throw new GemfireRestException("Server has encountered error while processing this request!", lee);
}catch(TimeoutException toe){
throw new GemfireRestException("Server has encountered timeout error while processing this request!", toe);
@@ -645,10 +646,7 @@ public abstract class AbstractBaseController {
protected String convertErrorAsJson(Throwable t) {
StringWriter writer = new StringWriter();
t.printStackTrace(new PrintWriter(writer));
- String returnString = writer.toString();
- returnString = returnString.replace("\n"," ");
- returnString = returnString.replace("\t"," ");
- return String.format("{\"message\" : \"%1$s\", \"stackTrace\" : \"%2$s\"}", t.getMessage(), returnString);
+ return String.format("{\"message\" : \"%1$s\", \"stackTrace\" : \"%2$s\"}", t.getMessage(), writer.toString());
}
protected Map<?,?> convertJsonToMap(final String jsonString) {
@@ -794,7 +792,7 @@ public abstract class AbstractBaseController {
throw new GemfireRestException(String.format("Resource (%1$s) configuration does not allow null keys!", regionNamePath), npe);
} catch(IllegalArgumentException iae) {
throw new GemfireRestException(String.format("Resource (%1$s) configuration does not allow requested operation on specified key!", regionNamePath), iae);
- } catch(org.apache.geode.distributed.LeaseExpiredException lee) {
+ } catch(LeaseExpiredException lee) {
throw new GemfireRestException("Server has encountered error while processing this request!", lee);
} catch(TimeoutException te) {
throw new GemfireRestException("Server has encountered timeout error while processing this request!", te);
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/BaseControllerAdvice.java
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/BaseControllerAdvice.java b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/BaseControllerAdvice.java
index a4f58b9..54dd9e5 100644
--- a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/BaseControllerAdvice.java
+++ b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/BaseControllerAdvice.java
@@ -20,20 +20,24 @@ package org.apache.geode.rest.internal.web.controllers;
import java.io.PrintWriter;
import java.io.StringWriter;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.rest.internal.web.exception.DataTypeNotSupportedException;
+import org.apache.geode.rest.internal.web.exception.GemfireRestException;
+import org.apache.geode.rest.internal.web.exception.MalformedJsonException;
+import org.apache.geode.rest.internal.web.exception.RegionNotFoundException;
+import org.apache.geode.rest.internal.web.exception.ResourceNotFoundException;
+import org.apache.geode.security.AuthenticationFailedException;
+import org.apache.geode.security.NotAuthorizedException;
import org.apache.logging.log4j.Logger;
+import org.apache.shiro.authc.AuthenticationException;
import org.springframework.http.HttpStatus;
+import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
-import org.apache.geode.internal.logging.LogService;
-import org.apache.geode.rest.internal.web.exception.DataTypeNotSupportedException;
-import org.apache.geode.rest.internal.web.exception.GemfireRestException;
-import org.apache.geode.rest.internal.web.exception.MalformedJsonException;
-import org.apache.geode.rest.internal.web.exception.RegionNotFoundException;
-import org.apache.geode.rest.internal.web.exception.ResourceNotFoundException;
/**
* The CrudControllerAdvice class handles exception thrown while serving the REST request
@@ -43,7 +47,7 @@ import org.apache.geode.rest.internal.web.exception.ResourceNotFoundException;
@ControllerAdvice
@SuppressWarnings("unused")
-public class BaseControllerAdvice extends AbstractBaseController{
+public class BaseControllerAdvice extends AbstractBaseController {
private static final Logger logger = LogService.getLogger();
@@ -121,6 +125,58 @@ public class BaseControllerAdvice extends AbstractBaseController{
}
/**
+ * Handles an AuthenticationFailedException thrown by a REST API web service endpoint, HTTP request handler method.
+ * <p/>
+ * @param cause the Exception causing the error.
+ * @return a ResponseEntity with an appropriate HTTP status code (403 - Forbidden)
+ */
+ @ExceptionHandler(AuthenticationFailedException.class)
+ @ResponseBody
+ @ResponseStatus(HttpStatus.UNAUTHORIZED)
+ public String handleException(final AuthenticationFailedException cause) {
+ return convertErrorAsJson(cause.getMessage());
+ }
+
+ /**
+ * Handles an AuthenticationException thrown by a REST API web service endpoint, HTTP request handler method.
+ * <p/>
+ * @param cause the Exception causing the error.
+ * @return a ResponseEntity with an appropriate HTTP status code (403 - Forbidden)
+ */
+ @ExceptionHandler(AuthenticationException.class)
+ @ResponseBody
+ @ResponseStatus(HttpStatus.UNAUTHORIZED)
+ public String handleException(final AuthenticationException cause) {
+ return convertErrorAsJson(cause.getMessage());
+ }
+
+ /**
+ * Handles an AccessDenied Exception thrown by a REST API web service endpoint, HTTP request handler method.
+ * <p/>
+ * @param cause the Exception causing the error.
+ * @return a ResponseEntity with an appropriate HTTP status code (403 - Forbidden)
+ */
+ @ExceptionHandler(AccessDeniedException.class)
+ @ResponseBody
+ @ResponseStatus(HttpStatus.FORBIDDEN)
+ public String handleException(final AccessDeniedException cause) {
+ return convertErrorAsJson(cause.getMessage());
+ }
+
+ /**
+ * Handles an NotAuthorized Exception thrown by a GeodeSecurityUtil.
+ * <p/>
+ * @param cause the Exception causing the error.
+ * @return a ResponseEntity with an appropriate HTTP status code (403 - Forbidden)
+ */
+ @ExceptionHandler(NotAuthorizedException.class)
+ @ResponseBody
+ @ResponseStatus(HttpStatus.FORBIDDEN)
+ public String handleException(final NotAuthorizedException cause) {
+ return convertErrorAsJson(cause.getMessage());
+ }
+
+ /**
* Handles any Exception thrown by a REST API web service endpoint, HTTP request handler method.
* <p/>
* @param cause the Exception causing the error.
@@ -134,13 +190,13 @@ public class BaseControllerAdvice extends AbstractBaseController{
final StringWriter stackTraceWriter = new StringWriter();
cause.printStackTrace(new PrintWriter(stackTraceWriter));
final String stackTrace = stackTraceWriter.toString();
-
+
if(logger.isDebugEnabled()){
- logger.debug(stackTrace);
+ logger.debug(stackTrace);
}
-
+
return convertErrorAsJson(cause.getMessage());
}
-
+
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/CommonCrudController.java
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/CommonCrudController.java b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/CommonCrudController.java
index b312884..232f034 100644
--- a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/CommonCrudController.java
+++ b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/CommonCrudController.java
@@ -21,15 +21,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
-import org.apache.logging.log4j.Logger;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiResponse;
+import com.wordnik.swagger.annotations.ApiResponses;
import org.apache.geode.cache.LowMemoryException;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.execute.Execution;
@@ -38,14 +32,20 @@ import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.cache.execute.ResultCollector;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.logging.LogService;
-import org.apache.geode.internal.util.ArrayUtils;
import org.apache.geode.rest.internal.web.controllers.support.RestServersResultCollector;
import org.apache.geode.rest.internal.web.exception.GemfireRestException;
+import org.apache.geode.rest.internal.web.util.ArrayUtils;
import org.apache.geode.rest.internal.web.util.JSONUtils;
+import org.apache.logging.log4j.Logger;
import org.json.JSONException;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
/**
* The CommonCrudController serves REST Requests related to listing regions,
@@ -71,19 +71,20 @@ public abstract class CommonCrudController extends AbstractBaseController {
)
@ApiResponses( {
@ApiResponse( code = 200, message = "OK." ),
- @ApiResponse( code = 500, message = "GemFire throws an error or exception." )
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
+ @ApiResponse( code = 500, message = "GemFire throws an error or exception." )
} )
public ResponseEntity<?> regions() {
-
+ securityService.authorizeDataRead();
if(logger.isDebugEnabled()){
logger.debug("Listing all resources (Regions) in GemFire...");
}
-
+ final HttpHeaders headers = new HttpHeaders();
+ headers.setLocation(toUri());
final Set<Region<?, ?>> regions = getCache().rootRegions();
String listRegionsAsJson = JSONUtils.formulateJsonForListRegions(regions, "regions");
- final HttpHeaders headers = new HttpHeaders();
- headers.setLocation(toUri());
- return new ResponseEntity<String>(listRegionsAsJson, headers, HttpStatus.OK);
+ return new ResponseEntity<>(listRegionsAsJson, headers, HttpStatus.OK);
}
/**
@@ -91,7 +92,7 @@ public abstract class CommonCrudController extends AbstractBaseController {
* @param region gemfire region
* @return JSON document containing result
*/
- @RequestMapping(method = RequestMethod.GET, value = "/{region}/keys",
+ @RequestMapping(method = RequestMethod.GET, value = "/{region}/keys",
produces = { MediaType.APPLICATION_JSON_VALUE } )
@ApiOperation(
value = "list all keys",
@@ -100,11 +101,13 @@ public abstract class CommonCrudController extends AbstractBaseController {
)
@ApiResponses( {
@ApiResponse( code = 200, message = "OK" ),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse( code = 404, message = "Region does not exist" ),
@ApiResponse( code = 500, message = "GemFire throws an error or exception" )
} )
- public ResponseEntity<?> keys(@PathVariable("region") String region){
-
+ public ResponseEntity<?> keys(@PathVariable("region") String region){
+ securityService.authorizeRegionRead(region);
if(logger.isDebugEnabled()){
logger.debug("Reading all Keys in Region ({})...", region);
}
@@ -116,7 +119,7 @@ public abstract class CommonCrudController extends AbstractBaseController {
String listKeysAsJson = JSONUtils.formulateJsonForListKeys(keys, "keys");
final HttpHeaders headers = new HttpHeaders();
headers.setLocation(toUri(region, "keys"));
- return new ResponseEntity<String>(listKeysAsJson, headers, HttpStatus.OK);
+ return new ResponseEntity<>(listKeysAsJson, headers, HttpStatus.OK);
}
/**
@@ -134,11 +137,15 @@ public abstract class CommonCrudController extends AbstractBaseController {
)
@ApiResponses( {
@ApiResponse( code = 200, message = "OK" ),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse( code = 404, message = "Region or key(s) does not exist" ),
@ApiResponse( code = 500, message = "GemFire throws an error or exception" )
} )
public ResponseEntity<?> delete(@PathVariable("region") String region,
- @PathVariable("keys") final String[] keys){
+ @PathVariable("keys") final String[] keys){
+ for (String key : keys)
+ securityService.authorizeRegionWrite(region, key);
if(logger.isDebugEnabled()){
logger.debug("Delete data for key {} on region {}", ArrayUtils.toString((Object[])keys), region);
}
@@ -146,7 +153,7 @@ public abstract class CommonCrudController extends AbstractBaseController {
region = decode(region);
deleteValues(region, (Object[])keys);
- return new ResponseEntity<Object>(HttpStatus.OK);
+ return new ResponseEntity<>(HttpStatus.OK);
}
/**
@@ -162,21 +169,27 @@ public abstract class CommonCrudController extends AbstractBaseController {
)
@ApiResponses( {
@ApiResponse( code = 200, message = "OK" ),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse( code = 404, message = "Region does not exist" ),
@ApiResponse( code = 500, message = "if GemFire throws an error or exception" )
} )
public ResponseEntity<?> delete(@PathVariable("region") String region) {
-
+ securityService.authorizeRegionWrite(region);
if(logger.isDebugEnabled()){
logger.debug("Deleting all data in Region ({})...", region);
}
-
+
region = decode(region);
deleteValues(region);
- return new ResponseEntity<Object>(HttpStatus.OK);
+ return new ResponseEntity<>(HttpStatus.OK);
}
-
+
+ /**
+ * Ping is not secured so that it may not be used to determine a valid username/password
+ * @return
+ */
@RequestMapping(method = { RequestMethod.GET, RequestMethod.HEAD }, value = "/ping")
@ApiOperation(
value = "Check Rest service status ",
@@ -188,7 +201,7 @@ public abstract class CommonCrudController extends AbstractBaseController {
@ApiResponse( code = 500, message = "if GemFire throws an error or exception" )
} )
public ResponseEntity<?> ping() {
- return new ResponseEntity<Object>(HttpStatus.OK);
+ return new ResponseEntity<>(HttpStatus.OK);
}
@RequestMapping(method = { RequestMethod.GET }, value = "/servers")
@@ -199,15 +212,17 @@ public abstract class CommonCrudController extends AbstractBaseController {
)
@ApiResponses( {
@ApiResponse( code = 200, message = "OK" ),
- @ApiResponse( code = 500, message = "if GemFire throws an error or exception" )
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
+ @ApiResponse( code = 500, message = "if GemFire throws an error or exception" )
} )
public ResponseEntity<?> servers() {
- Execution function = null;
-
+ securityService.authorizeClusterRead();
if(logger.isDebugEnabled()){
logger.debug("Executing function to get REST enabled gemfire nodes in the DS!");
}
-
+
+ Execution function;
try {
function = FunctionService.onMembers(getAllMembersInDS());
} catch(FunctionException fe) {
@@ -223,7 +238,7 @@ public abstract class CommonCrudController extends AbstractBaseController {
headers.setLocation(toUri("servers"));
try {
String functionResultAsJson = JSONUtils.convertCollectionToJson((ArrayList<Object>)functionResult);
- return new ResponseEntity<String>(functionResultAsJson, headers, HttpStatus.OK);
+ return new ResponseEntity<>(functionResultAsJson, headers, HttpStatus.OK);
} catch (JSONException e) {
throw new GemfireRestException("Could not convert function results into Restful (JSON) format!", e);
}
@@ -242,7 +257,5 @@ public abstract class CommonCrudController extends AbstractBaseController {
}catch (FunctionException fe){
throw new GemfireRestException("Server has encountered error while executing the function!", fe);
}
-
}
-
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/FunctionAccessController.java
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/FunctionAccessController.java b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/FunctionAccessController.java
index c31292b..8cec110 100644
--- a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/FunctionAccessController.java
+++ b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/FunctionAccessController.java
@@ -17,16 +17,25 @@
package org.apache.geode.rest.internal.web.controllers;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiResponse;
+import com.wordnik.swagger.annotations.ApiResponses;
import org.apache.geode.cache.LowMemoryException;
-import org.apache.geode.cache.execute.*;
+import org.apache.geode.cache.execute.Execution;
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionException;
+import org.apache.geode.cache.execute.FunctionService;
+import org.apache.geode.cache.execute.ResultCollector;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.rest.internal.web.exception.GemfireRestException;
import org.apache.geode.rest.internal.web.util.ArrayUtils;
import org.apache.geode.rest.internal.web.util.JSONUtils;
-import com.wordnik.swagger.annotations.Api;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
import org.apache.logging.log4j.Logger;
import org.json.JSONException;
import org.springframework.http.HttpHeaders;
@@ -35,9 +44,13 @@ import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.*;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
/**
* The FunctionsController class serving REST Requests related to the function execution
@@ -79,12 +92,14 @@ public class FunctionAccessController extends AbstractBaseController {
)
@ApiResponses({
@ApiResponse(code = 200, message = "OK."),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse(code = 500, message = "GemFire throws an error or exception.")
})
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public ResponseEntity<?> list() {
-
+ securityService.authorizeDataRead();
if (logger.isDebugEnabled()) {
logger.debug("Listing all registered Functions in GemFire...");
}
@@ -116,6 +131,8 @@ public class FunctionAccessController extends AbstractBaseController {
)
@ApiResponses({
@ApiResponse(code = 200, message = "OK."),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse(code = 500, message = "if GemFire throws an error or exception"),
@ApiResponse(code = 400, message = "if Function arguments specified as JSON document in the request body is invalid")
})
@@ -128,6 +145,7 @@ public class FunctionAccessController extends AbstractBaseController {
@RequestParam(value = "filter", required = false) final String[] filter,
@RequestBody(required = false) final String argsInBody
) {
+ securityService.authorizeDataWrite();
Execution function = null;
functionId = decode(functionId);
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/PdxBasedCrudController.java
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/PdxBasedCrudController.java b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/PdxBasedCrudController.java
index dd77316..c05845a 100644
--- a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/PdxBasedCrudController.java
+++ b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/PdxBasedCrudController.java
@@ -20,6 +20,16 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiResponse;
+import com.wordnik.swagger.annotations.ApiResponses;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.rest.internal.web.controllers.support.JSONTypes;
+import org.apache.geode.rest.internal.web.controllers.support.RegionData;
+import org.apache.geode.rest.internal.web.controllers.support.RegionEntryData;
+import org.apache.geode.rest.internal.web.exception.ResourceNotFoundException;
+import org.apache.geode.rest.internal.web.util.ArrayUtils;
import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -33,17 +43,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
-import org.apache.geode.internal.logging.LogService;
-import org.apache.geode.internal.util.ArrayUtils;
-import org.apache.geode.rest.internal.web.controllers.support.JSONTypes;
-import org.apache.geode.rest.internal.web.controllers.support.RegionData;
-import org.apache.geode.rest.internal.web.controllers.support.RegionEntryData;
-import org.apache.geode.rest.internal.web.exception.ResourceNotFoundException;
-import com.wordnik.swagger.annotations.Api;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
-
/**
* The PdxBasedCrudController class serving REST Requests related to the REST CRUD operation on region
* <p/>
@@ -88,6 +87,8 @@ public class PdxBasedCrudController extends CommonCrudController {
@ApiResponses( {
@ApiResponse( code = 201, message = "Created."),
@ApiResponse( code = 400, message = "Data specified (JSON doc) in the request body is invalid." ),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse( code = 404, message = "Region does not exist." ),
@ApiResponse( code = 409, message = "Key already exist in region."),
@ApiResponse( code = 500, message = "GemFire throws an error or exception.")
@@ -95,7 +96,7 @@ public class PdxBasedCrudController extends CommonCrudController {
public ResponseEntity<?> create(@PathVariable("region") String region,
@RequestParam(value = "key", required = false) String key,
@RequestBody final String json) {
-
+ securityService.authorizeRegionWrite(region);
key = generateKey(key);
if(logger.isDebugEnabled()){
@@ -141,12 +142,14 @@ public class PdxBasedCrudController extends CommonCrudController {
@ApiResponses( {
@ApiResponse( code = 200, message = "OK."),
@ApiResponse( code = 400, message = "Bad request." ),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse( code = 404, message = "Region does not exist." ),
@ApiResponse( code = 500, message = "GemFire throws an error or exception.")
} )
public ResponseEntity<?> read(@PathVariable("region") String region,
@RequestParam(value = "limit", defaultValue = DEFAULT_GETALL_RESULT_LIMIT) final String limit) {
-
+ securityService.authorizeRegionRead(region);
if(logger.isDebugEnabled()){
logger.debug("Reading all data in Region ({})...", region);
}
@@ -219,6 +222,8 @@ public class PdxBasedCrudController extends CommonCrudController {
@ApiResponses( {
@ApiResponse( code = 200, message = "OK."),
@ApiResponse( code = 400, message = "Bad Request."),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse( code = 404, message = "Region does not exist." ),
@ApiResponse( code = 500, message = "GemFire throws an error or exception.")
} )
@@ -226,7 +231,9 @@ public class PdxBasedCrudController extends CommonCrudController {
@PathVariable("region") String region,
@PathVariable("keys") final String[] keys,
@RequestParam(value = "ignoreMissingKey", required = false ) final String ignoreMissingKey) {
-
+
+ for (String key : keys)
+ securityService.authorizeRegionRead(region, key);
if(logger.isDebugEnabled()){
logger.debug("Reading data for keys ({}) in Region ({})",
ArrayUtils.toString(keys), region);
@@ -302,6 +309,8 @@ public class PdxBasedCrudController extends CommonCrudController {
@ApiResponses( {
@ApiResponse( code = 200, message = "OK."),
@ApiResponse( code = 400, message = "Bad Request."),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse( code = 404, message = "Region does not exist or if key is not mapped to some value for REPLACE or CAS."),
@ApiResponse( code = 409, message = "For CAS, @old value does not match to the current value in region" ),
@ApiResponse( code = 500, message = "GemFire throws an error or exception.")
@@ -310,7 +319,8 @@ public class PdxBasedCrudController extends CommonCrudController {
@PathVariable("keys") final String[] keys,
@RequestParam(value = "op", defaultValue = "PUT") final String opValue,
@RequestBody final String json) {
-
+ for (String key : keys)
+ securityService.authorizeRegionWrite(region, key);
if(logger.isDebugEnabled()){
logger.debug("updating key(s) for region ({}) ", region);
}
@@ -334,11 +344,13 @@ public class PdxBasedCrudController extends CommonCrudController {
@ApiResponses( {
@ApiResponse( code = 200, message = "OK."),
@ApiResponse( code = 400, message = "Bad request." ),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse( code = 404, message = "Region does not exist." ),
@ApiResponse( code = 500, message = "GemFire throws an error or exception.")
} )
public ResponseEntity<?> size(@PathVariable("region") String region) {
-
+ securityService.authorizeRegionRead(region);
if(logger.isDebugEnabled()){
logger.debug("Determining the number of entries in Region ({})...", region);
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/7b21520b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/QueryAccessController.java
----------------------------------------------------------------------
diff --git a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/QueryAccessController.java b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/QueryAccessController.java
index 4f059a4..2df95aa 100644
--- a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/QueryAccessController.java
+++ b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/QueryAccessController.java
@@ -19,20 +19,10 @@ package org.apache.geode.rest.internal.web.controllers;
import java.util.concurrent.ConcurrentHashMap;
-import org.apache.logging.log4j.Logger;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiResponse;
+import com.wordnik.swagger.annotations.ApiResponses;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.query.FunctionDomainException;
import org.apache.geode.cache.query.NameResolutionException;
@@ -48,10 +38,20 @@ import org.apache.geode.rest.internal.web.exception.GemfireRestException;
import org.apache.geode.rest.internal.web.exception.ResourceNotFoundException;
import org.apache.geode.rest.internal.web.util.JSONUtils;
import org.apache.geode.rest.internal.web.util.ValidationUtils;
-import com.wordnik.swagger.annotations.Api;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
+import org.apache.logging.log4j.Logger;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
/**
* The QueryingController class serves all HTTP REST requests related to the gemfire querying
@@ -86,37 +86,39 @@ public class QueryAccessController extends AbstractBaseController {
}
/**
- * list all parameterized Queries created in a Gemfire data node
+ * list all parametrized Queries created in a Gemfire data node
* @return result as a JSON document.
*/
@RequestMapping(method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
@ApiOperation(
- value = "list all parameterized queries",
- notes = "List all parameterized queries by id/name",
+ value = "list all parametrized queries",
+ notes = "List all parametrized queries by id/name",
response = void.class
)
@ApiResponses( {
- @ApiResponse( code = 200, message = "OK." ),
- @ApiResponse( code = 500, message = "if GemFire throws an error or exception" )
+ @ApiResponse( code = 200, message = "OK." ),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
+ @ApiResponse( code = 500, message = "if GemFire throws an error or exception" )
} )
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public ResponseEntity<?> list() {
-
+ securityService.authorizeDataRead();
if (logger.isDebugEnabled()) {
- logger.debug("Listing all parameterized Queries in GemFire...");
+ logger.debug("Listing all parametrized Queries in GemFire...");
}
- final Region<String, String> parameterizedQueryRegion = getQueryStore(PARAMETERIZED_QUERIES_REGION);
+ final Region<String, String> parametrizedQueryRegion = getQueryStore(PARAMETERIZED_QUERIES_REGION);
- String queryListAsJson = JSONUtils.formulateJsonForListQueriesCall(parameterizedQueryRegion);
+ String queryListAsJson = JSONUtils.formulateJsonForListQueriesCall(parametrizedQueryRegion);
final HttpHeaders headers = new HttpHeaders();
headers.setLocation(toUri("queries"));
return new ResponseEntity<String>(queryListAsJson, headers, HttpStatus.OK);
}
/**
- * Create a named, parameterized Query
+ * Create a named, parametrized Query
* @param queryId uniquely identify the query
* @param oqlInUrl OQL query string specified in a request URL
* @param oqlInBody OQL query string specified in a request body
@@ -124,23 +126,26 @@ public class QueryAccessController extends AbstractBaseController {
*/
@RequestMapping(method = RequestMethod.POST)
@ApiOperation(
- value = "create a parameterized Query",
- notes = "Prepare the specified parameterized query and assign the corresponding ID for lookup",
+ value = "create a parametrized Query",
+ notes = "Prepare the specified parametrized query and assign the corresponding ID for lookup",
response = void.class
)
@ApiResponses( {
@ApiResponse( code = 201, message = "Successfully created." ),
- @ApiResponse( code = 409, message = "QueryId already assigned to other query." ),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
+ @ApiResponse( code = 409, message = "QueryId already assigned to other query." ),
@ApiResponse( code = 500, message = "GemFire throws an error or exception." )
} )
public ResponseEntity<?> create(@RequestParam("id") final String queryId,
@RequestParam(value = "q", required = false) String oqlInUrl,
@RequestBody(required = false) final String oqlInBody)
{
+ securityService.authorizeDataWrite();
final String oqlStatement = validateQuery(oqlInUrl, oqlInBody);
if (logger.isDebugEnabled()) {
- logger.debug("Creating a named, parameterized Query ({}) with ID ({})...", oqlStatement, queryId);
+ logger.debug("Creating a named, parametrized Query ({}) with ID ({})...", oqlStatement, queryId);
}
// store the compiled OQL statement with 'queryId' as the Key into the hidden, ParameterizedQueries Region...
@@ -170,12 +175,14 @@ public class QueryAccessController extends AbstractBaseController {
)
@ApiResponses( {
@ApiResponse( code = 200, message = "OK." ),
- @ApiResponse( code = 500, message = "GemFire throws an error or exception" )
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
+ @ApiResponse( code = 500, message = "GemFire throws an error or exception" )
} )
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public ResponseEntity<String> runAdhocQuery(@RequestParam("q") String oql) {
-
+ securityService.authorizeDataRead();
if (logger.isDebugEnabled()) {
logger.debug("Running an adhoc Query ({})...", oql);
}
@@ -210,19 +217,21 @@ public class QueryAccessController extends AbstractBaseController {
}
/**
- * Run named parameterized Query with ID
+ * Run named parametrized Query with ID
* @param queryId id of the OQL string
* @param arguments query bind params required while executing query
* @return query result as a JSON document
*/
@RequestMapping(method = RequestMethod.POST, value = "/{query}", produces = {MediaType.APPLICATION_JSON_VALUE})
@ApiOperation(
- value = "run parameterized query",
+ value = "run parametrized query",
notes = "run the specified named query passing in scalar values for query parameters in the GemFire cluster",
response = void.class
)
@ApiResponses( {
@ApiResponse( code = 200, message = "Query successfully executed." ),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse( code = 400, message = "Query bind params specified as JSON document in the request body is invalid" ),
@ApiResponse( code = 500, message = "GemFire throws an error or exception" )
} )
@@ -231,6 +240,7 @@ public class QueryAccessController extends AbstractBaseController {
public ResponseEntity<String> runNamedQuery(@PathVariable("query") String queryId,
@RequestBody String arguments)
{
+ securityService.authorizeDataWrite();
if (logger.isDebugEnabled()) {
logger.debug("Running named Query with ID ({})...", queryId);
}
@@ -286,30 +296,32 @@ public class QueryAccessController extends AbstractBaseController {
}
/**
- * Update named, parameterized Query
+ * Update named, parametrized Query
* @param queryId uniquely identify the query
* @param oqlInUrl OQL query string specified in a request URL
* @param oqlInBody OQL query string specified in a request body
*/
@RequestMapping(method = RequestMethod.PUT, value = "/{query}")
@ApiOperation(
- value = "update parameterized query",
- notes = "Update named, parameterized query by ID",
+ value = "update parametrized query",
+ notes = "Update named, parametrized query by ID",
response = void.class
)
@ApiResponses( {
@ApiResponse( code = 200, message = "Updated successfully." ),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse( code = 404, message = "queryId does not exist." ),
@ApiResponse( code = 500, message = "GemFire throws an error or exception." )
} )
public ResponseEntity<?> update( @PathVariable("query") final String queryId,
@RequestParam(value = "q", required = false) String oqlInUrl,
@RequestBody(required = false) final String oqlInBody) {
-
+ securityService.authorizeDataWrite();
final String oqlStatement = validateQuery(oqlInUrl, oqlInBody);
if (logger.isDebugEnabled()) {
- logger.debug("Updating a named, parameterized Query ({}) with ID ({})...", oqlStatement, queryId);
+ logger.debug("Updating a named, parametrized Query ({}) with ID ({})...", oqlStatement, queryId);
}
// update the OQL statement with 'queryId' as the Key into the hidden, ParameterizedQueries Region...
@@ -320,26 +332,28 @@ public class QueryAccessController extends AbstractBaseController {
return new ResponseEntity<Object>(HttpStatus.OK);
}
- //delete named, parameterized query
+ //delete named, parametrized query
/**
- * Delete named, parameterized Query
+ * Delete named, parametrized Query
* @param queryId uniquely identify the query to be deleted
*/
@RequestMapping(method = RequestMethod.DELETE, value = "/{query}")
@ApiOperation(
- value = "delete parameterized query",
- notes = "delete named, parameterized query by ID",
+ value = "delete parametrized query",
+ notes = "delete named, parametrized query by ID",
response = void.class
)
@ApiResponses( {
@ApiResponse( code = 200, message = "Deleted successfully." ),
+ @ApiResponse( code = 401, message = "Invalid Username or Password." ),
+ @ApiResponse( code = 403, message = "Insufficient privileges for operation." ),
@ApiResponse( code = 404, message = "queryId does not exist." ),
@ApiResponse( code = 500, message = "GemFire throws an error or exception" )
} )
public ResponseEntity<?> delete(@PathVariable("query") final String queryId) {
-
+ securityService.authorizeDataWrite();
if (logger.isDebugEnabled()) {
- logger.debug("Deleting a named, parameterized Query with ID ({}).", queryId);
+ logger.debug("Deleting a named, parametrized Query with ID ({}).", queryId);
}
//delete the OQL statement with 'queryId' as the Key into the hidden,