AMBARI-6905. POST on /api/v1/persist fails for CLUSTER.OPERATE. (mahadev)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/0c46e95e Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/0c46e95e Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/0c46e95e Branch: refs/heads/branch-alerts-dev Commit: 0c46e95e646da932d644719377d2584fc2b026c6 Parents: c9fbc84 Author: Mahadev Konar <maha...@apache.org> Authored: Mon Aug 18 21:01:39 2014 -0700 Committer: Mahadev Konar <maha...@apache.org> Committed: Tue Aug 19 10:56:11 2014 -0700 ---------------------------------------------------------------------- .../AmbariAuthorizationFilter.java | 15 ++- .../AmbariAuthorizationFilterTest.java | 124 +++++++++++++++++++ 2 files changed, 136 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/0c46e95e/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java index 4ba8c7f..bc67cdb 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java @@ -54,9 +54,10 @@ public class AmbariAuthorizationFilter implements Filter { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; - SecurityContext context = SecurityContextHolder.getContext(); + SecurityContext context = getSecurityContext(); - if (context.getAuthentication() == null || !context.getAuthentication().isAuthenticated()) { + Authentication authentication = context.getAuthentication(); + if (authentication == null || !authentication.isAuthenticated()) { String token = httpRequest.getHeader(INTERNAL_TOKEN_HEADER); if (token != null) { context.setAuthentication(new InternalAuthenticationToken(token)); @@ -64,7 +65,6 @@ public class AmbariAuthorizationFilter implements Filter { } else { boolean authorized = false; - Authentication authentication = context.getAuthentication(); for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) { if (grantedAuthority instanceof AmbariGrantedAuthority) { @@ -93,6 +93,11 @@ public class AmbariAuthorizationFilter implements Filter { authorized = true; break; } + } else if (requestURI.matches("/api/v[0-9]+/persist.*")) { + if (permissionId.equals(PermissionEntity.CLUSTER_OPERATE_PERMISSION)) { + authorized = true; + break; + } } } } @@ -134,4 +139,8 @@ public class AmbariAuthorizationFilter implements Filter { } return value == null || value.length() == 0 ? defaultValue : value; } + + SecurityContext getSecurityContext() { + return SecurityContextHolder.getContext(); + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/0c46e95e/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java new file mode 100644 index 0000000..a950eb6 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java @@ -0,0 +1,124 @@ +/* + * 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.security.authorization; + +import org.apache.ambari.server.orm.entities.PermissionEntity; +import org.apache.ambari.server.orm.entities.PrivilegeEntity; +import org.easymock.EasyMock; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContext; + +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Collection; +import java.util.Collections; + +import static org.easymock.EasyMock.*; + +public class AmbariAuthorizationFilterTest { + + @Test + public void testDoFilter_postPersist_hasOperatePermission() throws Exception { + FilterChain chain = createNiceMock(FilterChain.class); + HttpServletRequest request = createNiceMock(HttpServletRequest.class); + HttpServletResponse response = createNiceMock(HttpServletResponse.class); + AmbariAuthorizationFilter filter = createMockBuilder(AmbariAuthorizationFilter.class) + .addMockedMethod("getSecurityContext").withConstructor().createMock(); + SecurityContext securityContext = createNiceMock(SecurityContext.class); + Authentication authentication = createNiceMock(Authentication.class); + AmbariGrantedAuthority authority = createNiceMock(AmbariGrantedAuthority.class); + PrivilegeEntity privilegeEntity = createNiceMock(PrivilegeEntity.class); + PermissionEntity permission = createNiceMock(PermissionEntity.class); + FilterConfig filterConfig = createNiceMock(FilterConfig.class); + + + expect(filterConfig.getInitParameter("realm")).andReturn("AuthFilter"); + expect(authentication.isAuthenticated()).andReturn(true); + expect(request.getRequestURI()).andReturn("/api/v1/persist/some_val"); + expect(authority.getPrivilegeEntity()).andReturn(privilegeEntity); + expect(privilegeEntity.getPermission()).andReturn(permission); + EasyMock.<Collection<? extends GrantedAuthority>>expect(authentication.getAuthorities()) + .andReturn(Collections.singletonList(authority)); + expect(filter.getSecurityContext()).andReturn(securityContext); + expect(securityContext.getAuthentication()).andReturn(authentication); + + expect(permission.getId()).andReturn(PermissionEntity.CLUSTER_OPERATE_PERMISSION); + + // expect continue filtering + chain.doFilter(request, response); + + replay(request, response, chain, filter, securityContext, authentication, authority, + privilegeEntity, permission, filterConfig); + + filter.init(filterConfig); + filter.doFilter(request, response, chain); + + verify(request, response, chain, filter, securityContext, authentication, authority, + privilegeEntity, permission, filterConfig); + } + + @Test + public void testDoFilter_postPersist_hasNoOperatePermission() throws Exception { + FilterChain chain = createNiceMock(FilterChain.class); + HttpServletRequest request = createNiceMock(HttpServletRequest.class); + HttpServletResponse response = createNiceMock(HttpServletResponse.class); + AmbariAuthorizationFilter filter = createMockBuilder(AmbariAuthorizationFilter.class) + .addMockedMethod("getSecurityContext").withConstructor().createMock(); + SecurityContext securityContext = createNiceMock(SecurityContext.class); + Authentication authentication = createNiceMock(Authentication.class); + AmbariGrantedAuthority authority = createNiceMock(AmbariGrantedAuthority.class); + PrivilegeEntity privilegeEntity = createNiceMock(PrivilegeEntity.class); + PermissionEntity permission = createNiceMock(PermissionEntity.class); + FilterConfig filterConfig = createNiceMock(FilterConfig.class); + + + expect(filterConfig.getInitParameter("realm")).andReturn("AuthFilter"); + expect(authentication.isAuthenticated()).andReturn(true); + expect(request.getRequestURI()).andReturn("/api/v1/persist/some_val"); + expect(authority.getPrivilegeEntity()).andReturn(privilegeEntity); + expect(privilegeEntity.getPermission()).andReturn(permission); + EasyMock.<Collection<? extends GrantedAuthority>>expect(authentication.getAuthorities()) + .andReturn(Collections.singletonList(authority)); + expect(filter.getSecurityContext()).andReturn(securityContext); + expect(securityContext.getAuthentication()).andReturn(authentication); + + + expect(request.getMethod()).andReturn("POST"); + expect(permission.getId()).andReturn(PermissionEntity.VIEW_USE_PERMISSION); + + // expect permission denial + response.setHeader("WWW-Authenticate", "Basic realm=\"AuthFilter\""); + response.sendError(HttpServletResponse.SC_FORBIDDEN, "You do not have permissions to access this resource."); + response.flushBuffer(); + + replay(request, response, chain, filter, securityContext, authentication, authority, + privilegeEntity, permission, filterConfig); + + filter.init(filterConfig); + filter.doFilter(request, response, chain); + + verify(request, response, chain, filter, securityContext, authentication, authority, + privilegeEntity, permission, filterConfig); + } +} \ No newline at end of file