/** * Applies Zookeeper ACLs if Kerberos is enabled. * @param cConf configuration object * @return Zookeeper ACLs */ static List<ACL> getACLs(CConfiguration cConf) { if (SecurityUtil.isKerberosEnabled(cConf)) { return ZooDefs.Ids.CREATOR_ALL_ACL; } LOG.warn("Not adding ACLs on keys in ZooKeeper as Kerberos is not enabled"); return ZooDefs.Ids.OPEN_ACL_UNSAFE; } }
@Nullable @Override public StreamConfig create(StreamId streamId, @Nullable Properties props) throws Exception { String specifiedOwnerPrincipal = props != null && props.containsKey(Constants.Security.PRINCIPAL) ? props.getProperty(Constants.Security.PRINCIPAL) : null; // need to enforce on the principal id if impersonation is involved KerberosPrincipalId effectiveOwner = SecurityUtil.getEffectiveOwner(ownerAdmin, streamId.getNamespaceId(), specifiedOwnerPrincipal); Principal requestingUser = authenticationContext.getPrincipal(); if (effectiveOwner != null) { authorizationEnforcer.enforce(effectiveOwner, requestingUser, Action.ADMIN); } ensureAccess(streamId, Action.ADMIN); return delegate.create(streamId, props); }
/** * Wrapper around {@link #validateKerberosPrincipal(KerberosPrincipalId)} to validate a principal in string format */ public static void validateKerberosPrincipal(String principal) { validateKerberosPrincipal(new KerberosPrincipalId(principal)); }
@Inject @VisibleForTesting public DefaultImpersonator(CConfiguration cConf, UGIProvider ugiProvider) { this.ugiProvider = ugiProvider; this.kerberosEnabled = SecurityUtil.isKerberosEnabled(cConf); // on kerberos disabled cluster the master principal will be null String masterPrincipal = SecurityUtil.getMasterPrincipal(cConf); try { masterShortUsername = masterPrincipal == null ? null : new KerberosName(masterPrincipal).getShortName(); } catch (IOException e) { Throwables.propagate(e); } }
public static void loginForMasterService(CConfiguration cConf) throws IOException, LoginException { String principal = getMasterPrincipal(cConf); String keytabPath = getMasterKeytabURI(cConf); if (UserGroupInformation.isSecurityEnabled()) { Path keytabFile = Paths.get(keytabPath); Preconditions.checkArgument(Files.isReadable(keytabFile), "Keytab file is not a readable file: %s", keytabFile); String expandedPrincipal = expandPrincipal(principal); LOG.info("Logging in as: principal={}, keytab={}", principal, keytabPath); UserGroupInformation.loginUserFromKeytab(expandedPrincipal, keytabPath); long delaySec = cConf.getLong(Constants.Security.KERBEROS_KEYTAB_RELOGIN_INTERVAL); Executors.newSingleThreadScheduledExecutor(Threads.createDaemonThreadFactory("Kerberos keytab renewal")) .scheduleWithFixedDelay(new Runnable() { @Override public void run() { try { UserGroupInformation.getLoginUser().checkTGTAndReloginFromKeytab(); } catch (IOException e) { LOG.error("Failed to relogin from keytab", e); } } }, delaySec, delaySec, TimeUnit.SECONDS); } }
public Map<String, String> getSystemProperties(Id.Program id) throws IOException, NamespaceNotFoundException { Map<String, String> systemArgs = Maps.newHashMap(); systemArgs.put(Constants.CLUSTER_NAME, cConf.get(Constants.CLUSTER_NAME, "")); systemArgs.put(Constants.AppFabric.APP_SCHEDULER_QUEUE, queueResolver.getQueue(id.getNamespace())); if (SecurityUtil.isKerberosEnabled(cConf)) { ImpersonationInfo impersonationInfo = SecurityUtil.createImpersonationInfo(ownerAdmin, cConf, id.toEntityId()); systemArgs.put(ProgramOptionConstants.PRINCIPAL, impersonationInfo.getPrincipal()); systemArgs.put(ProgramOptionConstants.APP_PRINCIPAL_EXISTS, String.valueOf(ownerAdmin.exists(id.toEntityId().getParent()))); } return systemArgs; } }
if (!isKerberosEnabled(cConf)) { LOG.info("Kerberos login is not enabled. To enable Kerberos login, enable {} and configure {} and {}", Constants.Security.KERBEROS_ENABLED, Constants.Security.CFG_CDAP_MASTER_KRB_PRINCIPAL, principal = expandPrincipal(principal);
private void verifyOwner(NamespacedEntityId entityId, @Nullable KerberosPrincipalId specifiedOwnerPrincipal) throws DatasetManagementException, UnauthorizedException { try { SecurityUtil.verifyOwnerPrincipal(entityId, specifiedOwnerPrincipal == null ? null : specifiedOwnerPrincipal.getPrincipal(), ownerAdmin); } catch (IOException e) { throw new DatasetManagementException(e.getMessage(), e); } }
@Test public void testNoKeytabPath() throws IOException { String user = "alice"; CConfiguration cConf = CConfiguration.create(); // this should throw a null pointer exception with proper message as what to set try { SecurityUtil.getKeytabURIforPrincipal(user, cConf); Assert.fail(); } catch (NullPointerException e) { // expected Assert.assertTrue(e.getMessage().contains(Constants.Security.KEYTAB_PATH)); } } }
@Test public void testExpandPrincipal() throws Exception { String localHostname = InetAddress.getLocalHost().getCanonicalHostName(); Assert.assertNull(SecurityUtil.expandPrincipal(null)); Assert.assertEquals("user/" + localHostname + "@REALM.NET", SecurityUtil.expandPrincipal("user/_HOST@REALM.NET")); Assert.assertEquals("user/abc.com@REALM.NET", SecurityUtil.expandPrincipal("user/abc.com@REALM.NET")); Assert.assertEquals("_HOST/abc.com@REALM.NET", SecurityUtil.expandPrincipal("_HOST/abc.com@REALM.NET")); Assert.assertEquals("_HOST/" + localHostname + "@REALM.NET", SecurityUtil.expandPrincipal("_HOST/_HOST@REALM.NET")); Assert.assertEquals("user/_host@REALM.NET", SecurityUtil.expandPrincipal("user/_host@REALM.NET")); }
SecurityUtil.enableKerberosLogin(configuration);
private ImpersonationInfo getPrincipalForEntity(ImpersonationRequest request) throws IOException { ImpersonationInfo impersonationInfo = SecurityUtil.createImpersonationInfo(ownerAdmin, cConf, request.getEntityId()); LOG.debug("Obtained impersonation info: {} for entity {}", impersonationInfo, request.getEntityId()); return impersonationInfo; }
public Map<String, String> getSystemProperties(Id.Program id) throws IOException, NamespaceNotFoundException { Map<String, String> systemArgs = Maps.newHashMap(); systemArgs.put(Constants.CLUSTER_NAME, cConf.get(Constants.CLUSTER_NAME, "")); systemArgs.put(Constants.AppFabric.APP_SCHEDULER_QUEUE, queueResolver.getQueue(id.getNamespace())); if (SecurityUtil.isKerberosEnabled(cConf)) { ImpersonationInfo impersonationInfo = SecurityUtil.createImpersonationInfo(ownerAdmin, cConf, id.toEntityId()); systemArgs.put(ProgramOptionConstants.PRINCIPAL, impersonationInfo.getPrincipal()); systemArgs.put(ProgramOptionConstants.APP_PRINCIPAL_EXISTS, String.valueOf(ownerAdmin.exists(id.toEntityId().getParent()))); } return systemArgs; } }
private void verifyOwner(NamespacedEntityId entityId, @Nullable KerberosPrincipalId specifiedOwnerPrincipal) throws DatasetManagementException, UnauthorizedException { try { SecurityUtil.verifyOwnerPrincipal(entityId, specifiedOwnerPrincipal == null ? null : specifiedOwnerPrincipal.getPrincipal(), ownerAdmin); } catch (IOException e) { throw new DatasetManagementException(e.getMessage(), e); } }
@Nullable @Override public ImpersonationInfo getImpersonationInfo(NamespacedEntityId entityId) throws IOException { entityId = getEffectiveEntity(entityId); if (!entityId.getEntityType().equals(EntityType.NAMESPACE)) { KerberosPrincipalId effectiveOwner = ownerStore.getOwner(entityId); if (effectiveOwner != null) { return new ImpersonationInfo(effectiveOwner.getPrincipal(), SecurityUtil.getKeytabURIforPrincipal(effectiveOwner.getPrincipal(), cConf)); } } // (CDAP-8176) Since no owner was found for the entity return namespace principal if present. NamespaceConfig nsConfig = getNamespaceConfig(entityId.getNamespaceId()); return nsConfig.getPrincipal() == null ? null : new ImpersonationInfo(nsConfig.getPrincipal(), nsConfig.getKeytabURI()); }
new File(keytabURI.getPath()) : localizeKeytab(locationFactory.create(keytabURI)); try { String expandedPrincipal = SecurityUtil.expandPrincipal(impersonationRequest.getPrincipal()); LOG.debug("Logging in as: principal={}, keytab={}", expandedPrincipal, localKeytabFile);
SecurityUtil.enableKerberosLogin(cConf);
DatasetServiceClient(final DiscoveryServiceClient discoveryClient, NamespaceId namespaceId, CConfiguration cConf, AuthenticationContext authenticationContext) { this.remoteClient = new RemoteClient( discoveryClient, Constants.Service.DATASET_MANAGER, new DefaultHttpRequestConfig(false), String.format("%s/namespaces/%s/data", Constants.Gateway.API_VERSION_3, namespaceId.getNamespace())); this.namespaceId = namespaceId; this.securityEnabled = cConf.getBoolean(Constants.Security.ENABLED); this.kerberosEnabled = SecurityUtil.isKerberosEnabled(cConf); this.authorizationEnabled = cConf.getBoolean(Constants.Security.Authorization.ENABLED); this.authenticationContext = authenticationContext; this.masterShortUserName = AuthorizationUtil.getEffectiveMasterUser(cConf); }
/** * Helper function to get the authorizing user for app deployment, the authorzing user will be the app owner if it * is present. If not, it will be the namespace owner. If that is also not present, it will be the user who is making * the request */ public static String getAppAuthorizingUser(OwnerAdmin ownerAdmin, AuthenticationContext authenticationContext, ApplicationId applicationId, @Nullable KerberosPrincipalId appOwner) throws IOException { KerberosPrincipalId effectiveOwner = SecurityUtil.getEffectiveOwner(ownerAdmin, applicationId.getNamespaceId(), appOwner == null ? null : appOwner.getPrincipal()); // CDAP-13154 If impersonation is configured for either the application or namespace the effective owner will be // a kerberos principal which can have different form // (refer: https://docs.oracle.com/cd/E21455_01/common/tutorials/kerberos_principal.html). For example it can be // a complete principal name (alice/somehost.net@someREALM). For authorization we need the enforcement to happen // on the username and not the complete principal. The user name is the shortname of the principal so return the // shortname as authorizing user. String appAuthorizingUser = effectiveOwner != null ? new KerberosName(effectiveOwner.getPrincipal()).getShortName() : authenticationContext.getPrincipal().getName(); LOG.trace("Returning {} as authorizing app user for {}", appAuthorizingUser, applicationId); return appAuthorizingUser; }
/** * Validates the given {@link NamespacedEntityId} to be supported by the {@link OwnerStore} * i.e. the entity can be associated with an owner. * Validated the given {@link KerberosPrincipalId} to be valid i.e. it can be used to create a * {@link org.apache.hadoop.security.authentication.util.KerberosName}. * See {@link SecurityUtil#validateKerberosPrincipal(KerberosPrincipalId)} * * @param entityId {@link NamespacedEntityId} to be validated * @param principalId {@link KerberosPrincipalId} to be validated */ protected final void validate(NamespacedEntityId entityId, KerberosPrincipalId principalId) { validate(entityId); SecurityUtil.validateKerberosPrincipal(principalId); }