View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.accumulo.core.security;
18  
19  import java.io.Serializable;
20  import java.io.UnsupportedEncodingException;
21  import java.nio.ByteBuffer;
22  import java.nio.charset.Charset;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.HashSet;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Set;
30  import java.util.TreeSet;
31  
32  import org.apache.accumulo.core.data.ArrayByteSequence;
33  import org.apache.accumulo.core.data.ByteSequence;
34  import org.apache.accumulo.core.util.ArgumentChecker;
35  import org.apache.accumulo.core.util.ByteBufferUtil;
36  import org.apache.commons.codec.binary.Base64;
37  
38  public class Authorizations implements Iterable<byte[]>, Serializable {
39    
40    private static final long serialVersionUID = 1L;
41    
42    private Set<ByteSequence> auths = new HashSet<ByteSequence>();
43    private List<byte[]> authsList = new ArrayList<byte[]>();
44    private List<byte[]> immutableList = Collections.unmodifiableList(authsList);
45    
46    private static final boolean[] validAuthChars = new boolean[256];
47    
48    public static final String HEADER = "!AUTH1:";
49  
50    static {
51      for (int i = 0; i < 256; i++) {
52        validAuthChars[i] = false;
53      }
54      
55      for (int i = 'a'; i <= 'z'; i++) {
56        validAuthChars[i] = true;
57      }
58      
59      for (int i = 'A'; i <= 'Z'; i++) {
60        validAuthChars[i] = true;
61      }
62      
63      for (int i = '0'; i <= '9'; i++) {
64        validAuthChars[i] = true;
65      }
66      
67      validAuthChars['_'] = true;
68      validAuthChars['-'] = true;
69      validAuthChars[':'] = true;
70      validAuthChars['.'] = true;
71      validAuthChars['/'] = true;
72    }
73    
74    static final boolean isValidAuthChar(byte b) {
75      return validAuthChars[0xff & b];
76    }
77    
78    private void checkAuths() {
79      Set<ByteSequence> sortedAuths = new TreeSet<ByteSequence>(auths);
80      
81      for (ByteSequence bs : sortedAuths) {
82        if (bs.length() == 0) {
83          throw new IllegalArgumentException("Empty authorization");
84        }
85        
86        authsList.add(bs.toArray());
87      }
88    }
89    
90    public Authorizations(Collection<byte[]> authorizations) {
91      ArgumentChecker.notNull(authorizations);
92      for (byte[] auth : authorizations)
93        auths.add(new ArrayByteSequence(auth));
94      checkAuths();
95    }
96    
97    public Authorizations(List<ByteBuffer> authorizations) {
98      ArgumentChecker.notNull(authorizations);
99      for (ByteBuffer buffer : authorizations) {
100       auths.add(new ArrayByteSequence(ByteBufferUtil.toBytes(buffer)));
101     }
102     checkAuths();
103   }
104   
105   /**
106    * @param authorizations
107    *          a serialized authorizations string produced by {@link #getAuthorizationsArray()} or {@link #serialize()}
108    */
109 
110   public Authorizations(byte[] authorizations) {
111     
112     ArgumentChecker.notNull(authorizations);
113 
114     String authsString = new String(authorizations);
115     if (authsString.startsWith(HEADER)) {
116       // its the new format
117       authsString = authsString.substring(HEADER.length());
118       if (authsString.length() > 0) {
119         for (String encAuth : authsString.split(",")) {
120           byte[] auth = Base64.decodeBase64(encAuth.getBytes());
121           auths.add(new ArrayByteSequence(auth));
122         }
123         checkAuths();
124       }
125     } else {
126       // its the old format
127       ArgumentChecker.notNull(authorizations);
128       if (authorizations.length > 0)
129         setAuthorizations(authsString.split(","));
130     }
131   }
132   
133   public Authorizations() {}
134   
135   /**
136    * 
137    * @param charset
138    *          used to convert each authorization to a byte array
139    * @param authorizations
140    *          array of authorizations
141    */
142   
143   public Authorizations(Charset charset, String... authorizations) {
144     setAuthorizations(charset, authorizations);
145   }
146 
147   public Authorizations(String... authorizations) {
148     setAuthorizations(authorizations);
149   }
150   
151   private void setAuthorizations(String... authorizations) {
152     setAuthorizations(Charset.defaultCharset(), authorizations);
153   }
154   
155   private void setAuthorizations(Charset charset, String... authorizations) {
156     ArgumentChecker.notNull(authorizations);
157     auths.clear();
158     for (String str : authorizations) {
159       str = str.trim();
160       try {
161         auths.add(new ArrayByteSequence(str.getBytes(charset.name())));
162       } catch (UnsupportedEncodingException e) {
163         throw new RuntimeException(e);
164       }
165     }
166     
167     checkAuths();
168   }
169   
170   public byte[] getAuthorizationsArray() {
171     return serialize().getBytes();
172   }
173   
174   public List<byte[]> getAuthorizations() {
175     return immutableList;
176   }
177   
178   public List<ByteBuffer> getAuthorizationsBB() {
179     return ByteBufferUtil.toByteBuffers(immutableList);
180   }
181   
182   public String toString() {
183     StringBuilder sb = new StringBuilder();
184     String sep = "";
185     for (ByteSequence auth : auths) {
186       sb.append(sep);
187       sep = ",";
188       sb.append(new String(auth.toArray()));
189     }
190     
191     return sb.toString();
192   }
193   
194   public boolean contains(byte[] auth) {
195     return auths.contains(new ArrayByteSequence(auth));
196   }
197   
198   public boolean contains(ByteSequence auth) {
199     return auths.contains(auth);
200   }
201   
202   public boolean equals(Object o) {
203     if (o == null) {
204       return false;
205     }
206     
207     if (o instanceof Authorizations) {
208       Authorizations ao = (Authorizations) o;
209       
210       return auths.equals(ao.auths);
211     }
212     
213     return false;
214   }
215   
216   public int hashCode() {
217     int result = 0;
218     for (ByteSequence b : auths)
219       result += b.hashCode();
220     return result;
221   }
222   
223   public int size() {
224     return auths.size();
225   }
226   
227   public boolean isEmpty() {
228     return auths.isEmpty();
229   }
230   
231   @Override
232   public Iterator<byte[]> iterator() {
233     return immutableList.iterator();
234   }
235   
236   public String serialize() {
237     StringBuilder sb = new StringBuilder(HEADER);
238     String sep = "";
239     for (byte[] auth : immutableList) {
240       sb.append(sep);
241       sep = ",";
242       sb.append(new String(Base64.encodeBase64(auth)));
243     }
244     
245     return sb.toString();
246   }
247 }