Repository: ambari Updated Branches: refs/heads/trunk 81dae66ea -> d84b2f57b
AMBARI-4338 Proper error message required for CSRF protection error (mpapirkovskyy via dlysnichenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/d84b2f57 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/d84b2f57 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/d84b2f57 Branch: refs/heads/trunk Commit: d84b2f57b532c8f6361b5d807dd375aa4280b44b Parents: 81dae66 Author: Lisnichenko Dmitro <dlysniche...@hortonworks.com> Authored: Wed Jul 16 16:30:03 2014 +0300 Committer: Lisnichenko Dmitro <dlysniche...@hortonworks.com> Committed: Wed Jul 16 16:30:03 2014 +0300 ---------------------------------------------------------------------- .../server/api/AmbariCsrfProtectionFilter.java | 58 +++++++++++++++++ .../ambari/server/controller/AmbariServer.java | 4 +- .../api/AmbariCsrfProtectionFilterTest.java | 66 ++++++++++++++++++++ 3 files changed, 126 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/d84b2f57/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariCsrfProtectionFilter.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariCsrfProtectionFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariCsrfProtectionFilter.java new file mode 100644 index 0000000..2325337 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariCsrfProtectionFilter.java @@ -0,0 +1,58 @@ +/* + * 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.ambari.server.api; + +import com.sun.jersey.spi.container.ContainerRequest; +import com.sun.jersey.spi.container.ContainerRequestFilter; +import org.apache.ambari.server.api.services.ResultStatus; +import org.apache.ambari.server.api.services.serializers.JsonSerializer; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class AmbariCsrfProtectionFilter implements ContainerRequestFilter { + private static final Set<String> IGNORED_METHODS; + private static final String CSRF_HEADER = "X-Requested-By"; + private static final String ERROR_MESSAGE = "CSRF protection is turned on. " + CSRF_HEADER + " HTTP header is required."; + private static final JsonSerializer JSON_SERIALIZER = new JsonSerializer(); + + static { + HashSet<String> methods = new HashSet<String>(); + methods.add("GET"); + methods.add("OPTIONS"); + methods.add("HEAD"); + + IGNORED_METHODS = Collections.unmodifiableSet(methods); + + } + + @Override + public ContainerRequest filter(ContainerRequest containerRequest) { + if (!IGNORED_METHODS.contains(containerRequest.getMethod()) && + !containerRequest.getRequestHeaders().containsKey(CSRF_HEADER)) { + throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity( + JSON_SERIALIZER.serializeError(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST, ERROR_MESSAGE)) + ).type(MediaType.TEXT_PLAIN_TYPE).build()); + } + return containerRequest; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/d84b2f57/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java index a515ec6..d71cb8c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java @@ -346,9 +346,9 @@ public class AmbariServer { if (configs.csrfProtectionEnabled()) { sh.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", - "com.sun.jersey.api.container.filter.CsrfProtectionFilter"); + "org.apache.ambari.server.api.AmbariCsrfProtectionFilter"); proxy.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", - "com.sun.jersey.api.container.filter.CsrfProtectionFilter"); + "com.sun.jersey.api.container.filter.AmbariCsrfProtectionFilter"); } //Set jetty thread pool http://git-wip-us.apache.org/repos/asf/ambari/blob/d84b2f57/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariCsrfProtectionFilterTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariCsrfProtectionFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariCsrfProtectionFilterTest.java new file mode 100644 index 0000000..f3ac9d9 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/api/AmbariCsrfProtectionFilterTest.java @@ -0,0 +1,66 @@ +/* + * 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.ambari.server.api; + +import com.sun.jersey.core.header.InBoundHeaders; +import com.sun.jersey.spi.container.ContainerRequest; +import org.junit.Test; + +import javax.ws.rs.WebApplicationException; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.junit.Assert.*; + +public class AmbariCsrfProtectionFilterTest { + + @Test + public void testGetMethod() { + AmbariCsrfProtectionFilter filter = new AmbariCsrfProtectionFilter(); + ContainerRequest containerRequest = createMock(ContainerRequest.class); + expect(containerRequest.getMethod()).andReturn("GET"); + replay(containerRequest); + assertEquals(containerRequest, filter.filter(containerRequest)); + } + + @Test(expected = WebApplicationException.class) + public void testPostNoXRequestedBy() { + AmbariCsrfProtectionFilter filter = new AmbariCsrfProtectionFilter(); + ContainerRequest containerRequest = createMock(ContainerRequest.class); + InBoundHeaders headers = new InBoundHeaders(); + expect(containerRequest.getMethod()).andReturn("POST"); + expect(containerRequest.getRequestHeaders()).andReturn(headers); + replay(containerRequest); + filter.filter(containerRequest); + } + + @Test + public void testPostXRequestedBy() { + AmbariCsrfProtectionFilter filter = new AmbariCsrfProtectionFilter(); + ContainerRequest containerRequest = createMock(ContainerRequest.class); + InBoundHeaders headers = new InBoundHeaders(); + headers.add("X-Requested-By","anything"); + expect(containerRequest.getMethod()).andReturn("GET"); + expect(containerRequest.getRequestHeaders()).andReturn(headers); + replay(containerRequest); + assertEquals(containerRequest, filter.filter(containerRequest)); + } + +}