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,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.hadoop.hdfs.web.oauth2;
020
021import org.apache.hadoop.classification.InterfaceAudience;
022import org.apache.hadoop.classification.InterfaceStability;
023import org.apache.hadoop.util.Timer;
024
025/**
026 * Access tokens generally expire.  This timer helps keep track of that.
027 */
028@InterfaceAudience.Public
029@InterfaceStability.Evolving
030public class AccessTokenTimer {
031  public static final long EXPIRE_BUFFER_MS = 30 * 1000L;
032
033  private final Timer timer;
034
035  /**
036   * When the current access token will expire in milliseconds since
037   * epoch.
038   */
039  private long nextRefreshMSSinceEpoch;
040
041  public AccessTokenTimer() {
042    this(new Timer());
043  }
044
045  /**
046   *
047   * @param timer Timer instance for unit testing
048   */
049  public AccessTokenTimer(Timer timer) {
050    this.timer = timer;
051    this.nextRefreshMSSinceEpoch = 0;
052  }
053
054  /**
055   * Set when the access token will expire as reported by the oauth server,
056   * ie in seconds from now.
057   * @param expiresIn Access time expiration as reported by OAuth server
058   */
059  public void setExpiresIn(String expiresIn) {
060    this.nextRefreshMSSinceEpoch = convertExpiresIn(timer, expiresIn);
061  }
062
063  /**
064   * Set when the access token will expire in milliseconds from epoch,
065   * as required by the WebHDFS configuration.  This is a bit hacky and lame.
066   *
067   * @param expiresInMSSinceEpoch Access time expiration in ms since epoch.
068   */
069  public void setExpiresInMSSinceEpoch(String expiresInMSSinceEpoch){
070    this.nextRefreshMSSinceEpoch = Long.parseLong(expiresInMSSinceEpoch);
071  }
072
073  /**
074   * Get next time we should refresh the token.
075   *
076   * @return Next time since epoch we'll need to refresh the token.
077   */
078  public long getNextRefreshMSSinceEpoch() {
079    return nextRefreshMSSinceEpoch;
080  }
081
082  /**
083   * Return true if the current token has expired or will expire within the
084   * EXPIRE_BUFFER_MS (to give ample wiggle room for the call to be made to
085   * the server).
086   */
087  public boolean shouldRefresh() {
088    long lowerLimit = nextRefreshMSSinceEpoch - EXPIRE_BUFFER_MS;
089    long currTime = timer.now();
090    return currTime > lowerLimit;
091  }
092
093  /**
094   * The expires_in param from OAuth is in seconds-from-now.  Convert to
095   * milliseconds-from-epoch
096   */
097  static Long convertExpiresIn(Timer timer, String expiresInSecs) {
098    long expiresSecs = Long.parseLong(expiresInSecs);
099    long expiresMs = expiresSecs * 1000;
100    return timer.now() + expiresMs;
101  }
102
103}