/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.vertexium.security;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.*;
/**
* A collection of authorization strings.
*/
public class Authorizations implements Iterable<byte[]>, Serializable, AuthorizationContainer {
private static final long serialVersionUID = 1L;
private Set<ByteSequence> auths = new HashSet<ByteSequence>();
private List<byte[]> authsList = new ArrayList<byte[]>(); // sorted order
/**
* An empty set of authorizations.
*/
public static final Authorizations EMPTY = new Authorizations();
private static final boolean[] validAuthChars = new boolean[256];
static {
for (int i = 0; i < 256; i++) {
validAuthChars[i] = false;
}
for (int i = 'a'; i <= 'z'; i++) {
validAuthChars[i] = true;
}
for (int i = 'A'; i <= 'Z'; i++) {
validAuthChars[i] = true;
}
for (int i = '0'; i <= '9'; i++) {
validAuthChars[i] = true;
}
validAuthChars['_'] = true;
validAuthChars['-'] = true;
validAuthChars[':'] = true;
validAuthChars['.'] = true;
validAuthChars['/'] = true;
}
static final boolean isValidAuthChar(byte b) {
return validAuthChars[0xff & b];
}
private void checkAuths() {
Set<ByteSequence> sortedAuths = new TreeSet<ByteSequence>(auths);
for (ByteSequence bs : sortedAuths) {
if (bs.length() == 0) {
throw new IllegalArgumentException("Empty authorization");
}
authsList.add(bs.toArray());
}
}
/**
* Constructs an authorization object from a collection of string authorizations that have each already been encoded as UTF-8 bytes. Warning: This method does
* not verify that each encoded string is valid UTF-8.
*
* @param authorizations collection of authorizations, as strings encoded in UTF-8
* @throws IllegalArgumentException if authorizations is null
* @see #Authorizations(String...)
*/
public Authorizations(Collection<byte[]> authorizations) {
for (byte[] auth : authorizations)
auths.add(new ArrayByteSequence(auth));
checkAuths();
}
/**
* Constructs an authorization object from a list of string authorizations that have each already been encoded as UTF-8 bytes. Warning: This method does not
* verify that each encoded string is valid UTF-8.
*
* @param authorizations list of authorizations, as strings encoded in UTF-8 and placed in buffers
* @throws IllegalArgumentException if authorizations is null
* @see #Authorizations(String...)
*/
public Authorizations(List<ByteBuffer> authorizations) {
for (ByteBuffer buffer : authorizations) {
auths.add(new ArrayByteSequence(ByteBufferUtil.toBytes(buffer)));
}
checkAuths();
}
/**
* Constructs an empty set of authorizations.
*
* @see #Authorizations(String...)
*/
public Authorizations() {
}
/**
* Constructs an authorizations object from a set of human-readable authorizations.
*
* @param authorizations array of authorizations
* @throws IllegalArgumentException if authorizations is null
*/
public Authorizations(String... authorizations) {
setAuthorizations(authorizations);
}
private void setAuthorizations(String... authorizations) {
auths.clear();
for (String str : authorizations) {
str = str.trim();
auths.add(new ArrayByteSequence(str.getBytes(Constants.UTF8)));
}
checkAuths();
}
/**
* Gets the authorizations in sorted order. The returned list is not modifiable.
*
* @return authorizations, each as a string encoded in UTF-8
* @see #Authorizations(Collection)
*/
public List<byte[]> getAuthorizations() {
ArrayList<byte[]> copy = new ArrayList<byte[]>(authsList.size());
for (byte[] auth : authsList) {
byte[] bytes = new byte[auth.length];
System.arraycopy(auth, 0, bytes, 0, auth.length);
copy.add(bytes);
}
return Collections.unmodifiableList(copy);
}
/**
* Gets the authorizations in sorted order. The returned list is not modifiable.
*
* @return authorizations, each as a string encoded in UTF-8 and within a buffer
*/
public List<ByteBuffer> getAuthorizationsBB() {
ArrayList<ByteBuffer> copy = new ArrayList<ByteBuffer>(authsList.size());
for (byte[] auth : authsList) {
byte[] bytes = new byte[auth.length];
System.arraycopy(auth, 0, bytes, 0, auth.length);
copy.add(ByteBuffer.wrap(bytes));
}
return Collections.unmodifiableList(copy);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
String sep = "";
for (ByteSequence auth : auths) {
sb.append(sep);
sep = ",";
sb.append(new String(auth.toArray(), Constants.UTF8));
}
return sb.toString();
}
/**
* Checks whether this object contains the given authorization.
*
* @param auth authorization, as a string encoded in UTF-8
* @return true if authorization is in this collection
*/
public boolean contains(byte[] auth) {
return auths.contains(new ArrayByteSequence(auth));
}
/**
* Checks whether this object contains the given authorization. Warning: This method does not verify that the encoded string is valid UTF-8.
*
* @param auth authorization, as a string encoded in UTF-8
* @return true if authorization is in this collection
*/
@Override
public boolean contains(ByteSequence auth) {
return auths.contains(auth);
}
/**
* Checks whether this object contains the given authorization.
*
* @param auth authorization
* @return true if authorization is in this collection
*/
public boolean contains(String auth) {
return auths.contains(new ArrayByteSequence(auth));
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o instanceof Authorizations) {
Authorizations ao = (Authorizations) o;
return auths.equals(ao.auths);
}
return false;
}
@Override
public int hashCode() {
int result = 0;
for (ByteSequence b : auths)
result += b.hashCode();
return result;
}
/**
* Gets the size of this collection of authorizations.
*
* @return collection size
*/
public int size() {
return auths.size();
}
/**
* Checks if this collection of authorizations is empty.
*
* @return true if this collection contains no authorizations
*/
public boolean isEmpty() {
return auths.isEmpty();
}
@Override
public Iterator<byte[]> iterator() {
return getAuthorizations().iterator();
}
}