View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.mapreduce;
19  
20  import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_FAMILY;
21  import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
22  import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABEL_QUALIFIER;
23  
24  import java.io.ByteArrayOutputStream;
25  import java.io.DataOutputStream;
26  import java.io.IOException;
27  import java.util.ArrayList;
28  import java.util.HashMap;
29  import java.util.List;
30  import java.util.Map;
31  
32  import org.apache.hadoop.classification.InterfaceAudience;
33  import org.apache.hadoop.conf.Configuration;
34  import org.apache.hadoop.hbase.KeyValue;
35  import org.apache.hadoop.hbase.KeyValue.Type;
36  import org.apache.hadoop.hbase.Tag;
37  import org.apache.hadoop.hbase.client.HTable;
38  import org.apache.hadoop.hbase.client.Result;
39  import org.apache.hadoop.hbase.client.ResultScanner;
40  import org.apache.hadoop.hbase.client.Scan;
41  import org.apache.hadoop.hbase.mapreduce.ImportTsv.TsvParser.BadTsvLineException;
42  import org.apache.hadoop.hbase.security.visibility.Authorizations;
43  import org.apache.hadoop.hbase.security.visibility.ExpressionExpander;
44  import org.apache.hadoop.hbase.security.visibility.ExpressionParser;
45  import org.apache.hadoop.hbase.security.visibility.ParseException;
46  import org.apache.hadoop.hbase.security.visibility.VisibilityUtils;
47  import org.apache.hadoop.hbase.security.visibility.expression.ExpressionNode;
48  import org.apache.hadoop.hbase.security.visibility.expression.LeafExpressionNode;
49  import org.apache.hadoop.hbase.security.visibility.expression.NonLeafExpressionNode;
50  import org.apache.hadoop.hbase.security.visibility.expression.Operator;
51  import org.apache.hadoop.hbase.util.Bytes;
52  import org.apache.hadoop.io.WritableUtils;
53  
54  /**
55   * An utility class that helps the mapper and reducers used with visibility to
56   * scan the visibility_labels and helps in parsing and expanding the visibility
57   * tags
58   * 
59   */
60  @InterfaceAudience.Private
61  public class LabelExpander {
62    private Configuration conf;
63    private ExpressionParser parser = new ExpressionParser();
64    private ExpressionExpander expander = new ExpressionExpander();
65  
66    public LabelExpander(Configuration conf) {
67      this.conf = conf;
68    }
69  
70    private Map<String, Integer> labels;
71  
72    // TODO : The code repeats from that in Visibility Controller.. Refactoring
73    // may be needed
74    public List<Tag> createVisibilityTags(String visibilityLabelsExp) throws IOException,
75        BadTsvLineException {
76      ExpressionNode node = null;
77      try {
78        node = parser.parse(visibilityLabelsExp);
79      } catch (ParseException e) {
80        throw new BadTsvLineException(e.getMessage());
81      }
82      node = expander.expand(node);
83      List<Tag> tags = new ArrayList<Tag>();
84      ByteArrayOutputStream baos = new ByteArrayOutputStream();
85      DataOutputStream dos = new DataOutputStream(baos);
86      if (node.isSingleNode()) {
87        writeLabelOrdinalsToStream(node, dos);
88        tags.add(new Tag(VisibilityUtils.VISIBILITY_TAG_TYPE, baos.toByteArray()));
89        baos.reset();
90      } else {
91        NonLeafExpressionNode nlNode = (NonLeafExpressionNode) node;
92        if (nlNode.getOperator() == Operator.OR) {
93          for (ExpressionNode child : nlNode.getChildExps()) {
94            writeLabelOrdinalsToStream(child, dos);
95            tags.add(new Tag(VisibilityUtils.VISIBILITY_TAG_TYPE, baos.toByteArray()));
96            baos.reset();
97          }
98        } else {
99          writeLabelOrdinalsToStream(nlNode, dos);
100         tags.add(new Tag(VisibilityUtils.VISIBILITY_TAG_TYPE, baos.toByteArray()));
101         baos.reset();
102       }
103     }
104     return tags;
105   }
106 
107   private void writeLabelOrdinalsToStream(ExpressionNode node, DataOutputStream dos)
108       throws IOException, BadTsvLineException {
109     if (node.isSingleNode()) {
110       String identifier = null;
111       int labelOrdinal = 0;
112       if (node instanceof LeafExpressionNode) {
113         identifier = ((LeafExpressionNode) node).getIdentifier();
114         if (this.labels.get(identifier) != null) {
115           labelOrdinal = this.labels.get(identifier);
116         }
117       } else {
118         // This is a NOT node.
119         LeafExpressionNode lNode = (LeafExpressionNode) ((NonLeafExpressionNode) node)
120             .getChildExps().get(0);
121         identifier = lNode.getIdentifier();
122         if (this.labels.get(identifier) != null) {
123           labelOrdinal = this.labels.get(identifier);
124           labelOrdinal = -1 * labelOrdinal; // Store NOT node as -ve ordinal.
125         }
126       }
127       if (labelOrdinal == 0) {
128         throw new BadTsvLineException("Invalid visibility label " + identifier);
129       }
130       WritableUtils.writeVInt(dos, labelOrdinal);
131     } else {
132       List<ExpressionNode> childExps = ((NonLeafExpressionNode) node).getChildExps();
133       for (ExpressionNode child : childExps) {
134         writeLabelOrdinalsToStream(child, dos);
135       }
136     }
137   }
138 
139   private void createLabels() throws IOException {
140     // This scan should be done by user with global_admin previliges.. Ensure
141     // that it works
142     HTable visibilityLabelsTable = null;
143     ResultScanner scanner = null;
144     try {
145       labels = new HashMap<String, Integer>();
146       visibilityLabelsTable = new HTable(conf, LABELS_TABLE_NAME.getName());
147       Scan scan = new Scan();
148       scan.setAuthorizations(new Authorizations(VisibilityUtils.SYSTEM_LABEL));
149       scan.addColumn(LABELS_TABLE_FAMILY, LABEL_QUALIFIER);
150       scanner = visibilityLabelsTable.getScanner(scan);
151       while (true) {
152         Result next = scanner.next();
153         if (next == null) {
154           break;
155         }
156         byte[] row = next.getRow();
157         byte[] value = next.getValue(LABELS_TABLE_FAMILY, LABEL_QUALIFIER);
158         labels.put(Bytes.toString(value), Bytes.toInt(row));
159       }
160     } finally {
161       try {
162         if (scanner != null) {
163           scanner.close();
164         }
165       } finally {
166         if (visibilityLabelsTable != null) {
167           visibilityLabelsTable.close();
168         }
169       }
170     }
171   }
172 
173   /**
174    * Creates a kv from the cell visibility expr specified in the ImportTSV and uses it as the
175    * visibility tag in the kv
176    * @param rowKeyOffset
177    * @param rowKeyLength
178    * @param family
179    * @param familyOffset
180    * @param familyLength
181    * @param qualifier
182    * @param qualifierOffset
183    * @param qualifierLength
184    * @param ts
185    * @param put
186    * @param lineBytes
187    * @param columnOffset
188    * @param columnLength
189    * @param cellVisibilityExpr
190    * @return KeyValue from the cell visibility expr
191    * @throws IOException
192    * @throws BadTsvLineException
193    */
194   public KeyValue createKVFromCellVisibilityExpr(int rowKeyOffset, int rowKeyLength, byte[] family,
195       int familyOffset, int familyLength, byte[] qualifier, int qualifierOffset,
196       int qualifierLength, long ts, Type put, byte[] lineBytes, int columnOffset, int columnLength,
197       String cellVisibilityExpr) throws IOException, BadTsvLineException {
198     if(this.labels == null  && cellVisibilityExpr != null) {
199       createLabels();
200     }
201     KeyValue kv = null;
202     if (cellVisibilityExpr != null) {
203       // Apply the expansion and parsing here
204       List<Tag> visibilityTags = createVisibilityTags(cellVisibilityExpr);
205       kv = new KeyValue(lineBytes, rowKeyOffset, rowKeyLength, family, familyOffset, familyLength,
206           qualifier, qualifierOffset, qualifierLength, ts, KeyValue.Type.Put, lineBytes, columnOffset,
207           columnLength, visibilityTags);
208     } else {
209       kv = new KeyValue(lineBytes, rowKeyOffset, rowKeyLength, family, familyOffset, familyLength,
210           qualifier, qualifierOffset, qualifierLength, ts, KeyValue.Type.Put, lineBytes, columnOffset,
211           columnLength);
212     }
213     return kv;
214   }
215 }