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 */
018
019package org.apache.hadoop.hbase.security.access;
020
021import java.util.Collection;
022import java.util.Map;
023
024import org.apache.yetus.audience.InterfaceAudience;
025import org.apache.hadoop.hbase.Cell;
026import org.apache.hadoop.hbase.TableName;
027import org.apache.hadoop.hbase.security.User;
028import org.apache.hadoop.hbase.util.Bytes;
029
030import org.apache.hbase.thirdparty.com.google.common.base.Joiner;
031
032/**
033 * Represents the result of an authorization check for logging and error
034 * reporting.
035 */
036@InterfaceAudience.Private
037public class AuthResult {
038  private boolean allowed;
039  private final String namespace;
040  private final TableName table;
041  private final Permission.Action action;
042  private final String request;
043  private String reason;
044  private final User user;
045  private AuthResult.Params params;
046
047  // "family" and "qualifier" should only be used if "families" is null.
048  private final byte[] family;
049  private final byte[] qualifier;
050  private final Map<byte[], ? extends Collection<?>> families;
051
052  public AuthResult(boolean allowed, String request, String reason, User user,
053      Permission.Action action, TableName table, byte[] family, byte[] qualifier) {
054    this.allowed = allowed;
055    this.request = request;
056    this.reason = reason;
057    this.user = user;
058    this.table = table;
059    this.family = family;
060    this.qualifier = qualifier;
061    this.action = action;
062    this.families = null;
063    this.namespace = null;
064    this.params = new Params().setTableName(table).setFamily(family).setQualifier(qualifier);
065  }
066
067  public AuthResult(boolean allowed, String request, String reason, User user,
068        Permission.Action action, TableName table,
069        Map<byte[], ? extends Collection<?>> families) {
070    this.allowed = allowed;
071    this.request = request;
072    this.reason = reason;
073    this.user = user;
074    this.table = table;
075    this.family = null;
076    this.qualifier = null;
077    this.action = action;
078    this.families = families;
079    this.namespace = null;
080    this.params = new Params().setTableName(table).setFamilies(families);
081  }
082
083  public AuthResult(boolean allowed, String request, String reason, User user,
084        Permission.Action action, String namespace) {
085    this.allowed = allowed;
086    this.request = request;
087    this.reason = reason;
088    this.user = user;
089    this.namespace = namespace;
090    this.action = action;
091    this.table = null;
092    this.family = null;
093    this.qualifier = null;
094    this.families = null;
095    this.params = new Params().setNamespace(namespace);
096  }
097
098  public boolean isAllowed() {
099    return allowed;
100  }
101
102  public User getUser() {
103    return user;
104  }
105
106  public String getReason() {
107    return reason;
108  }
109
110  public TableName getTableName() {
111    return table;
112  }
113
114  public byte[] getFamily() {
115    return family;
116  }
117
118  public byte[] getQualifier() {
119    return qualifier;
120  }
121
122  public Permission.Action getAction() {
123    return action;
124  }
125
126  public String getRequest() {
127    return request;
128  }
129
130  public Params getParams() { return this.params;}
131
132  public void setAllowed(boolean allowed) {
133    this.allowed = allowed;
134  }
135
136  public void setReason(String reason) {
137    this.reason = reason;
138  }
139
140  private static String toFamiliesString(Map<byte[], ? extends Collection<?>> families,
141      byte[] family, byte[] qual) {
142    StringBuilder sb = new StringBuilder();
143    if (families != null) {
144      boolean first = true;
145      for (Map.Entry<byte[], ? extends Collection<?>> entry : families.entrySet()) {
146        String familyName = Bytes.toString(entry.getKey());
147        if (entry.getValue() != null && !entry.getValue().isEmpty()) {
148          for (Object o : entry.getValue()) {
149            String qualifier;
150            if (o instanceof byte[]) {
151              qualifier = Bytes.toString((byte[])o);
152            } else if (o instanceof Cell) {
153              Cell c = (Cell) o;
154              qualifier = Bytes.toString(c.getQualifierArray(), c.getQualifierOffset(),
155                  c.getQualifierLength());
156            } else {
157              // Shouldn't really reach this?
158              qualifier = o.toString();
159            }
160            if (!first) {
161              sb.append("|");
162            }
163            first = false;
164            sb.append(familyName).append(":").append(qualifier);
165          }
166        } else {
167          if (!first) {
168            sb.append("|");
169          }
170          first = false;
171          sb.append(familyName);
172        }
173      }
174    } else if (family != null) {
175      sb.append(Bytes.toString(family));
176      if (qual != null) {
177        sb.append(":").append(Bytes.toString(qual));
178      }
179    }
180    return sb.toString();
181  }
182
183  public String toContextString() {
184    StringBuilder sb = new StringBuilder();
185    String familiesString = toFamiliesString(families, family, qualifier);
186    sb.append("(user=")
187        .append(user != null ? user.getName() : "UNKNOWN")
188        .append(", ");
189    sb.append("scope=")
190        .append(namespace != null ? namespace :
191            table == null ? "GLOBAL" : table.getNameWithNamespaceInclAsString())
192        .append(", ");
193    if(namespace == null && familiesString.length() > 0) {
194      sb.append("family=")
195        .append(familiesString)
196        .append(", ");
197    }
198    String paramsString = params.toString();
199    if(paramsString.length() > 0) {
200      sb.append("params=[")
201          .append(paramsString)
202          .append("],");
203    }
204    sb.append("action=")
205        .append(action != null ? action.toString() : "")
206        .append(")");
207    return sb.toString();
208  }
209
210  @Override
211  public String toString() {
212    return "AuthResult" + toContextString();
213  }
214
215  public static AuthResult allow(String request, String reason, User user,
216      Permission.Action action, String namespace) {
217    return new AuthResult(true, request, reason, user, action, namespace);
218  }
219
220  public static AuthResult allow(String request, String reason, User user,
221      Permission.Action action, TableName table, byte[] family, byte[] qualifier) {
222    return new AuthResult(true, request, reason, user, action, table, family, qualifier);
223  }
224
225  public static AuthResult allow(String request, String reason, User user,
226      Permission.Action action, TableName table,
227      Map<byte[], ? extends Collection<?>> families) {
228    return new AuthResult(true, request, reason, user, action, table, families);
229  }
230
231  public static AuthResult deny(String request, String reason, User user,
232      Permission.Action action, String namespace) {
233    return new AuthResult(false, request, reason, user, action, namespace);
234  }
235
236  public static AuthResult deny(String request, String reason, User user,
237      Permission.Action action, TableName table, byte[] family, byte[] qualifier) {
238    return new AuthResult(false, request, reason, user, action, table, family, qualifier);
239  }
240
241  public static AuthResult deny(String request, String reason, User user,
242        Permission.Action action, TableName table,
243        Map<byte[], ? extends Collection<?>> families) {
244    return new AuthResult(false, request, reason, user, action, table, families);
245  }
246
247  public String toFamilyString() {
248    return toFamiliesString(families, family, qualifier);
249  }
250
251  public static class Params {
252    private String namespace = null;
253    private TableName tableName = null;
254    private Map<byte[], ? extends Collection<?>> families = null;
255    byte[] family = null;
256    byte[] qualifier = null;
257
258    public Params setNamespace(String namespace) {
259      this.namespace = namespace;
260      return this;
261    }
262
263    public Params setTableName(TableName table) {
264      this.tableName = table;
265      return this;
266    }
267
268    public Params setFamilies(Map<byte[], ? extends Collection<?>> families) {
269      this.families = families;
270      return this;
271    }
272
273    public Params setFamily(byte[] family) {
274      this.family = family;
275      return this;
276    }
277
278    public Params setQualifier(byte[] qualifier) {
279      this.qualifier = qualifier;
280      return this;
281    }
282
283    @Override
284    public String toString() {
285      String familiesString = toFamiliesString(families, family, qualifier);
286      String[] params = new String[] {
287          namespace != null ? "namespace=" + namespace : null,
288          tableName != null ? "table=" + tableName.getNameWithNamespaceInclAsString() : null,
289          familiesString.length() > 0 ? "family=" + familiesString : null
290      };
291      return Joiner.on(",").skipNulls().join(params);
292    }
293
294  }
295}