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