001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.security.visibility; 019 020import java.io.IOException; 021import org.apache.hadoop.conf.Configuration; 022import org.apache.hadoop.hbase.zookeeper.ZKListener; 023import org.apache.hadoop.hbase.zookeeper.ZKUtil; 024import org.apache.hadoop.hbase.zookeeper.ZKWatcher; 025import org.apache.hadoop.hbase.zookeeper.ZNodePaths; 026import org.apache.yetus.audience.InterfaceAudience; 027import org.apache.zookeeper.KeeperException; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031/** 032 * A zk watcher that watches the labels table znode. This would create a znode 033 * /hbase/visibility_labels and will have a serialized form of a set of labels in the system. 034 */ 035@InterfaceAudience.Private 036public class ZKVisibilityLabelWatcher extends ZKListener { 037 038 private static final Logger LOG = LoggerFactory.getLogger(ZKVisibilityLabelWatcher.class); 039 private static final String VISIBILITY_LABEL_ZK_PATH = "zookeeper.znode.visibility.label.parent"; 040 private static final String DEFAULT_VISIBILITY_LABEL_NODE = "visibility/labels"; 041 private static final String VISIBILITY_USER_AUTHS_ZK_PATH = 042 "zookeeper.znode.visibility.user.auths.parent"; 043 private static final String DEFAULT_VISIBILITY_USER_AUTHS_NODE = "visibility/user_auths"; 044 045 private VisibilityLabelsCache labelsCache; 046 private String labelZnode; 047 private String userAuthsZnode; 048 049 public ZKVisibilityLabelWatcher(ZKWatcher watcher, VisibilityLabelsCache labelsCache, 050 Configuration conf) { 051 super(watcher); 052 this.labelsCache = labelsCache; 053 String labelZnodeParent = conf.get(VISIBILITY_LABEL_ZK_PATH, DEFAULT_VISIBILITY_LABEL_NODE); 054 String userAuthsZnodeParent = 055 conf.get(VISIBILITY_USER_AUTHS_ZK_PATH, DEFAULT_VISIBILITY_USER_AUTHS_NODE); 056 this.labelZnode = ZNodePaths.joinZNode(watcher.getZNodePaths().baseZNode, labelZnodeParent); 057 this.userAuthsZnode = 058 ZNodePaths.joinZNode(watcher.getZNodePaths().baseZNode, userAuthsZnodeParent); 059 } 060 061 public void start() throws KeeperException { 062 watcher.registerListener(this); 063 ZKUtil.createWithParents(watcher, labelZnode); 064 ZKUtil.createWithParents(watcher, userAuthsZnode); 065 byte[] data = ZKUtil.getDataAndWatch(watcher, labelZnode); 066 if (data != null && data.length > 0) { 067 refreshVisibilityLabelsCache(data); 068 } 069 data = ZKUtil.getDataAndWatch(watcher, userAuthsZnode); 070 if (data != null && data.length > 0) { 071 refreshUserAuthsCache(data); 072 } 073 } 074 075 private void refreshVisibilityLabelsCache(byte[] data) { 076 try { 077 this.labelsCache.refreshLabelsCache(data); 078 } catch (IOException ioe) { 079 LOG.error("Failed parsing data from labels table " + " from zk", ioe); 080 } 081 } 082 083 private void refreshUserAuthsCache(byte[] data) { 084 try { 085 this.labelsCache.refreshUserAuthsCache(data); 086 } catch (IOException ioe) { 087 LOG.error("Failed parsing data from labels table " + " from zk", ioe); 088 } 089 } 090 091 @Override 092 public void nodeCreated(String path) { 093 if (path.equals(labelZnode) || path.equals(userAuthsZnode)) { 094 try { 095 ZKUtil.watchAndCheckExists(watcher, path); 096 } catch (KeeperException ke) { 097 LOG.error("Error setting watcher on node " + path, ke); 098 // only option is to abort 099 watcher.abort("ZooKeeper error obtaining label node children", ke); 100 } 101 } 102 } 103 104 @Override 105 public void nodeDeleted(String path) { 106 // There is no case of visibility labels path to get deleted. 107 } 108 109 @Override 110 public void nodeDataChanged(String path) { 111 if (path.equals(labelZnode) || path.equals(userAuthsZnode)) { 112 try { 113 watcher.syncOrTimeout(path); 114 byte[] data = ZKUtil.getDataAndWatch(watcher, path); 115 if (path.equals(labelZnode)) { 116 refreshVisibilityLabelsCache(data); 117 } else { 118 refreshUserAuthsCache(data); 119 } 120 } catch (KeeperException ke) { 121 LOG.error("Error reading data from zookeeper for node " + path, ke); 122 // only option is to abort 123 watcher.abort("ZooKeeper error getting data for node " + path, ke); 124 } 125 } 126 } 127 128 @Override 129 public void nodeChildrenChanged(String path) { 130 // We are not dealing with child nodes under the label znode or userauths znode. 131 } 132 133 /** 134 * Write a labels mirror or user auths mirror into zookeeper 135 * @param labelsOrUserAuths true for writing labels and false for user auths. 136 */ 137 public void writeToZookeeper(byte[] data, boolean labelsOrUserAuths) { 138 String znode = this.labelZnode; 139 if (!labelsOrUserAuths) { 140 znode = this.userAuthsZnode; 141 } 142 try { 143 ZKUtil.updateExistingNodeData(watcher, znode, data, -1); 144 } catch (KeeperException e) { 145 LOG.error("Failed writing to " + znode, e); 146 watcher.abort("Failed writing node " + znode + " to zookeeper", e); 147 } 148 } 149}