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.token;
020
021import javax.crypto.SecretKey;
022
023import java.io.DataInput;
024import java.io.DataOutput;
025import java.io.IOException;
026import java.time.Instant;
027import java.util.Arrays;
028
029import org.apache.yetus.audience.InterfaceAudience;
030import org.apache.hadoop.hbase.util.Bytes;
031import org.apache.hadoop.io.Writable;
032import org.apache.hadoop.io.WritableUtils;
033
034/**
035 * Represents a secret key used for signing and verifying authentication tokens
036 * by {@link AuthenticationTokenSecretManager}.
037 */
038@InterfaceAudience.Private
039public class AuthenticationKey implements Writable {
040  private volatile int id;
041  private volatile long expirationDate;
042  private volatile SecretKey secret;
043
044  public AuthenticationKey() {
045    // for Writable
046  }
047
048  public AuthenticationKey(int keyId, long expirationDate, SecretKey key) {
049    this.id = keyId;
050    this.expirationDate = expirationDate;
051    this.secret = key;
052  }
053
054  public int getKeyId() {
055    return id;
056  }
057
058  public long getExpiration() {
059    return expirationDate;
060  }
061
062  public void setExpiration(long timestamp) {
063    expirationDate = timestamp;
064  }
065
066  SecretKey getKey() {
067    return secret;
068  }
069
070  @Override
071  public int hashCode() {
072    int result = id;
073    result = 31 * result + (int) (expirationDate ^ (expirationDate >>> 32));
074    result = 31 * result + ((secret == null) ? 0 : Arrays.hashCode(secret.getEncoded()));
075    return result;
076  }
077
078  @Override
079  public boolean equals(Object obj) {
080    if (obj == null || !(obj instanceof AuthenticationKey)) {
081      return false;
082    }
083    AuthenticationKey other = (AuthenticationKey)obj;
084    return id == other.getKeyId() &&
085        expirationDate == other.getExpiration() &&
086        (secret == null ? other.getKey() == null :
087            other.getKey() != null &&
088                Bytes.equals(secret.getEncoded(), other.getKey().getEncoded()));       
089  }
090
091  @Override
092  public String toString() {
093    StringBuilder buf = new StringBuilder();
094    buf.append("AuthenticationKey[")
095       .append("id=").append(id)
096       .append(", expiration=").append(Instant.ofEpochMilli(this.expirationDate))
097      .append(", obj=").append(super.toString())
098      .append("]");
099    return buf.toString();
100  }
101
102  @Override
103  public void write(DataOutput out) throws IOException {
104    WritableUtils.writeVInt(out, id);
105    WritableUtils.writeVLong(out, expirationDate);
106    if (secret == null) {
107      WritableUtils.writeVInt(out, -1);
108    } else {
109      byte[] keyBytes = secret.getEncoded();
110      WritableUtils.writeVInt(out, keyBytes.length);
111      out.write(keyBytes);
112    }
113  }
114
115  @Override
116  public void readFields(DataInput in) throws IOException {
117    id = WritableUtils.readVInt(in);
118    expirationDate = WritableUtils.readVLong(in);
119    int keyLength = WritableUtils.readVInt(in);
120    if (keyLength < 0) {
121      secret = null;
122    } else {
123      byte[] keyBytes = new byte[keyLength];
124      in.readFully(keyBytes);
125      secret = AuthenticationTokenSecretManager.createSecretKey(keyBytes);
126    }
127  }
128}