| /* |
| * 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.apache.accumulo.core.clientImpl; |
| |
| import static java.nio.charset.StandardCharsets.UTF_8; |
| |
| import java.nio.ByteBuffer; |
| import java.util.Base64; |
| |
| import org.apache.accumulo.core.client.AccumuloClient; |
| import org.apache.accumulo.core.client.AccumuloSecurityException; |
| import org.apache.accumulo.core.client.security.tokens.AuthenticationToken; |
| import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.AuthenticationTokenSerializer; |
| import org.apache.accumulo.core.clientImpl.thrift.SecurityErrorCode; |
| import org.apache.accumulo.core.securityImpl.thrift.TCredentials; |
| |
| /** |
| * A wrapper for internal use. This class carries the instance, principal, and authentication token |
| * for use in the public API, in a non-serialized form. This is important, so that the |
| * authentication token carried in a {@link AccumuloClient} can be destroyed, invalidating future |
| * RPC operations from that {@link AccumuloClient}. |
| * <p> |
| * See ACCUMULO-1312 |
| * |
| * @since 1.6.0 |
| */ |
| public class Credentials { |
| |
| private String principal; |
| private AuthenticationToken token; |
| |
| /** |
| * Creates a new credentials object. |
| * |
| * @param principal |
| * unique identifier for the entity (e.g. a user or service) authorized for these |
| * credentials |
| * @param token |
| * authentication token used to prove that the principal for these credentials has been |
| * properly verified |
| */ |
| public Credentials(String principal, AuthenticationToken token) { |
| this.principal = principal; |
| this.token = token; |
| } |
| |
| /** |
| * Gets the principal. |
| * |
| * @return unique identifier for the entity (e.g. a user or service) authorized for these |
| * credentials |
| */ |
| public String getPrincipal() { |
| return principal; |
| } |
| |
| /** |
| * Gets the authentication token. |
| * |
| * @return authentication token used to prove that the principal for these credentials has been |
| * properly verified |
| */ |
| public AuthenticationToken getToken() { |
| return token; |
| } |
| |
| /** |
| * Converts the current object to the relevant thrift type. The object returned from this contains |
| * a non-destroyable version of the {@link AuthenticationToken}, so this should be used just |
| * before placing on the wire, and references to it should be tightly controlled. |
| * |
| * @param instanceID |
| * Accumulo instance ID |
| * @return Thrift credentials |
| * @throws RuntimeException |
| * if the authentication token has been destroyed (expired) |
| */ |
| public TCredentials toThrift(String instanceID) { |
| TCredentials tCreds = new TCredentials(getPrincipal(), getToken().getClass().getName(), |
| ByteBuffer.wrap(AuthenticationTokenSerializer.serialize(getToken())), instanceID); |
| if (getToken().isDestroyed()) |
| throw new RuntimeException("Token has been destroyed", |
| new AccumuloSecurityException(getPrincipal(), SecurityErrorCode.TOKEN_EXPIRED)); |
| return tCreds; |
| } |
| |
| /** |
| * Converts a given thrift object to our internal Credentials representation. |
| * |
| * @param serialized |
| * a Thrift encoded set of credentials |
| * @return a new Credentials instance; destroy the token when you're done. |
| */ |
| public static Credentials fromThrift(TCredentials serialized) { |
| return new Credentials(serialized.getPrincipal(), AuthenticationTokenSerializer |
| .deserialize(serialized.getTokenClassName(), serialized.getToken())); |
| } |
| |
| /** |
| * Converts the current object to a serialized form. The object returned from this contains a |
| * non-destroyable version of the {@link AuthenticationToken}, so references to it should be |
| * tightly controlled. |
| * |
| * @return serialized form of these credentials |
| */ |
| public final String serialize() { |
| return (getPrincipal() == null ? "-" |
| : Base64.getEncoder().encodeToString(getPrincipal().getBytes(UTF_8))) |
| + ":" |
| + (getToken() == null ? "-" |
| : Base64.getEncoder().encodeToString(getToken().getClass().getName().getBytes(UTF_8))) |
| + ":" + (getToken() == null ? "-" : Base64.getEncoder() |
| .encodeToString(AuthenticationTokenSerializer.serialize(getToken()))); |
| } |
| |
| /** |
| * Converts the serialized form to an instance of {@link Credentials}. The original serialized |
| * form will not be affected. |
| * |
| * @param serializedForm |
| * serialized form of credentials |
| * @return deserialized credentials |
| */ |
| public static final Credentials deserialize(String serializedForm) { |
| String[] split = serializedForm.split(":", 3); |
| String principal = |
| split[0].equals("-") ? null : new String(Base64.getDecoder().decode(split[0]), UTF_8); |
| String tokenType = |
| split[1].equals("-") ? null : new String(Base64.getDecoder().decode(split[1]), UTF_8); |
| AuthenticationToken token = null; |
| if (!split[2].equals("-")) { |
| byte[] tokenBytes = Base64.getDecoder().decode(split[2]); |
| token = AuthenticationTokenSerializer.deserialize(tokenType, tokenBytes); |
| } |
| return new Credentials(principal, token); |
| } |
| |
| @Override |
| public int hashCode() { |
| return getPrincipal() == null ? 0 : getPrincipal().hashCode(); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj == null || !(obj instanceof Credentials)) |
| return false; |
| Credentials other = Credentials.class.cast(obj); |
| boolean pEq = getPrincipal() == null ? (other.getPrincipal() == null) |
| : (getPrincipal().equals(other.getPrincipal())); |
| if (!pEq) |
| return false; |
| return getToken() == null ? (other.getToken() == null) : (getToken().equals(other.getToken())); |
| } |
| |
| @Override |
| public String toString() { |
| return getClass().getName() + ":" + getPrincipal() + ":" |
| + (getToken() == null ? null : getToken().getClass().getName()) + ":<hidden>"; |
| } |
| } |