| /** |
| * 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.sentry.api.generic.thrift; |
| |
| import static org.hamcrest.core.Is.is; |
| import static org.junit.Assert.assertThat; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.security.PrivilegedExceptionAction; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.log4j.Level; |
| import org.apache.log4j.Logger; |
| import org.apache.sentry.provider.db.log.appender.AuditLoggerTestAppender; |
| import org.apache.sentry.provider.db.log.util.CommandUtil; |
| import org.apache.sentry.provider.db.log.util.Constants; |
| import org.apache.sentry.service.thrift.SentryServiceIntegrationBase; |
| import org.codehaus.jettison.json.JSONObject; |
| import org.junit.After; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Sets; |
| |
| public class TestAuditLogForSentryGenericService extends SentryServiceIntegrationBase { |
| |
| private SentryGenericServiceClient client; |
| private static final String COMPONENT = "SQOOP"; |
| private static final org.slf4j.Logger LOGGER = LoggerFactory |
| .getLogger(TestAuditLogForSentryGenericService.class); |
| |
| @BeforeClass |
| public static void setup() throws Exception { |
| SentryServiceIntegrationBase.setup(); |
| Logger logger = Logger.getLogger("sentry.generic.authorization.ddl.logger"); |
| AuditLoggerTestAppender testAppender = new AuditLoggerTestAppender(); |
| logger.addAppender(testAppender); |
| logger.setLevel(Level.INFO); |
| } |
| |
| @Override |
| @After |
| public void after() { |
| try { |
| runTestAsSubject(new TestOperation() { |
| @Override |
| public void runTestAsSubject() throws Exception { |
| Set<TSentryRole> tRoles = client.listAllRoles(SentryServiceIntegrationBase.ADMIN_USER, COMPONENT); |
| for (TSentryRole tRole : tRoles) { |
| client.dropRole(SentryServiceIntegrationBase.ADMIN_USER, tRole.getRoleName(), COMPONENT); |
| } |
| if (client != null) { |
| client.close(); |
| } |
| } |
| }); |
| } catch (Exception e) { |
| // log the exception |
| LOGGER.warn("Exception happened after test case.", e); |
| } finally { |
| policyFilePath.delete(); |
| } |
| } |
| |
| /** |
| * use the generic client to connect sentry service |
| */ |
| @Override |
| public void connectToSentryService() throws Exception { |
| if (SentryServiceIntegrationBase.kerberos) { |
| this.client = SentryServiceIntegrationBase.clientUgi.doAs(new PrivilegedExceptionAction<SentryGenericServiceClient>() { |
| @Override |
| public SentryGenericServiceClient run() throws Exception { |
| return SentryGenericServiceClientFactory.create(SentryServiceIntegrationBase.conf); |
| } |
| }); |
| } else { |
| this.client = SentryGenericServiceClientFactory.create(SentryServiceIntegrationBase.conf); |
| } |
| } |
| |
| @Test |
| public void testAuditLogForGenericModel() throws Exception { |
| runTestAsSubject(new TestOperation() { |
| @Override |
| public void runTestAsSubject() throws Exception { |
| String requestorUserName = SentryServiceIntegrationBase.ADMIN_USER; |
| Set<String> requestorUserGroupNames = Sets.newHashSet(SentryServiceIntegrationBase.ADMIN_GROUP); |
| String roleName = "admin_r"; |
| String testGroupName = "g1"; |
| String action = "all"; |
| String service = "sentryService"; |
| setLocalGroupMapping(requestorUserName, requestorUserGroupNames); |
| writePolicyFile(); |
| |
| // test the audit log for create role, success |
| client.createRole(requestorUserName, roleName, COMPONENT); |
| Map<String, String> fieldValueMap = new HashMap<String, String>(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_CREATE_ROLE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, "CREATE ROLE " + roleName); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.TRUE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| |
| // test the audit log for create role, failed |
| try { |
| client.createRole(requestorUserName, roleName, COMPONENT); |
| fail("Exception should have been thrown"); |
| } catch (Exception e) { |
| fieldValueMap.clear(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_CREATE_ROLE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, "CREATE ROLE " + roleName); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.FALSE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| } |
| |
| // test the audit log for add role to group, success |
| client.grantRoleToGroups(requestorUserName, roleName, COMPONENT, |
| Sets.newHashSet(testGroupName)); |
| fieldValueMap.clear(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_ADD_ROLE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, "GRANT ROLE " + roleName |
| + " TO GROUP " + testGroupName); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.TRUE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| |
| // test the audit log for add role to group, failed |
| try { |
| client.grantRoleToGroups(requestorUserName, "invalidRole", COMPONENT, |
| Sets.newHashSet(testGroupName)); |
| fail("Exception should have been thrown"); |
| } catch (Exception e) { |
| fieldValueMap.clear(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_ADD_ROLE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, "GRANT ROLE invalidRole TO GROUP " |
| + testGroupName); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.FALSE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| } |
| |
| // test the audit log for grant privilege, success |
| TSentryPrivilege privilege = new TSentryPrivilege(COMPONENT, service, Lists.newArrayList( |
| new TAuthorizable("resourceType1", "resourceName1"), new TAuthorizable("resourceType2", |
| "resourceName2")), action); |
| client.grantPrivilege(requestorUserName, roleName, COMPONENT, privilege); |
| fieldValueMap.clear(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_GRANT_PRIVILEGE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, |
| "GRANT ALL ON resourceType1 resourceName1 resourceType2 resourceName2 TO ROLE " |
| + roleName); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.TRUE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| |
| // for error audit log |
| TSentryPrivilege invalidPrivilege = new TSentryPrivilege(COMPONENT, service, |
| Lists.newArrayList(new TAuthorizable("resourceType1", "resourceName1")), |
| "invalidAction"); |
| // test the audit log for grant privilege, failed |
| try { |
| client.grantPrivilege(requestorUserName, roleName, COMPONENT, invalidPrivilege); |
| fail("Exception should have been thrown"); |
| } catch (Exception e) { |
| fieldValueMap.clear(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_GRANT_PRIVILEGE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, |
| "GRANT INVALIDACTION ON resourceType1 resourceName1 TO ROLE " + roleName); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.FALSE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| } |
| |
| // test the audit log for revoke privilege, success |
| client.revokePrivilege(requestorUserName, roleName, COMPONENT, privilege); |
| fieldValueMap.clear(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_REVOKE_PRIVILEGE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, |
| "REVOKE ALL ON resourceType1 resourceName1 resourceType2 resourceName2 FROM ROLE " |
| + roleName); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.TRUE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| |
| // test the audit log for revoke privilege, failed |
| try { |
| client.revokePrivilege(requestorUserName, "invalidRole", COMPONENT, invalidPrivilege); |
| fail("Exception should have been thrown"); |
| } catch (Exception e) { |
| fieldValueMap.clear(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_REVOKE_PRIVILEGE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, |
| "REVOKE INVALIDACTION ON resourceType1 resourceName1 FROM ROLE invalidRole"); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.FALSE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| } |
| |
| // test the audit log for delete role from group, success |
| client.revokeRoleFromGroups(requestorUserName, roleName, COMPONENT, |
| Sets.newHashSet(testGroupName)); |
| fieldValueMap.clear(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_DELETE_ROLE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, "REVOKE ROLE " + roleName |
| + " FROM GROUP " + testGroupName); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.TRUE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| // test the audit log for delete role from group, failed |
| try { |
| client.revokeRoleFromGroups(requestorUserName, "invalidRole", COMPONENT, |
| Sets.newHashSet(testGroupName)); |
| fail("Exception should have been thrown"); |
| } catch (Exception e) { |
| fieldValueMap.clear(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_DELETE_ROLE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, |
| "REVOKE ROLE invalidRole FROM GROUP " + testGroupName); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.FALSE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| } |
| // test the audit log for drop role, success |
| client.dropRole(requestorUserName, roleName, COMPONENT); |
| fieldValueMap.clear(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_DROP_ROLE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, "DROP ROLE " + roleName); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.TRUE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| // test the audit log for drop role, failed |
| try { |
| client.dropRole(requestorUserName, roleName, COMPONENT); |
| fail("Exception should have been thrown"); |
| } catch (Exception e) { |
| fieldValueMap.clear(); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION, Constants.OPERATION_DROP_ROLE); |
| fieldValueMap.put(Constants.LOG_FIELD_COMPONENT, COMPONENT); |
| fieldValueMap.put(Constants.LOG_FIELD_OPERATION_TEXT, "DROP ROLE " + roleName); |
| fieldValueMap.put(Constants.LOG_FIELD_ALLOWED, Constants.FALSE); |
| fieldValueMap.put(Constants.LOG_FIELD_IP_ADDRESS, null); |
| assertAuditLog(fieldValueMap); |
| } |
| } |
| }); |
| } |
| |
| private void assertAuditLog(Map<String, String> fieldValueMap) throws Exception { |
| assertThat(AuditLoggerTestAppender.getLastLogLevel(), is(Level.INFO)); |
| JSONObject jsonObject = new JSONObject(AuditLoggerTestAppender.getLastLogEvent()); |
| if (fieldValueMap != null) { |
| for (Map.Entry<String, String> entry : fieldValueMap.entrySet()) { |
| String entryKey = entry.getKey(); |
| if (Constants.LOG_FIELD_IP_ADDRESS.equals(entryKey)) { |
| assertTrue(CommandUtil.assertIPInAuditLog(jsonObject.get(entryKey).toString())); |
| } else { |
| assertTrue(entry.getValue().equalsIgnoreCase(jsonObject.get(entryKey).toString())); |
| } |
| } |
| } |
| } |
| } |