com.helger.photon.security.token.accesstoken.AccessToken Maven / Gradle / Ivy
/*
* Copyright (C) 2014-2023 Philip Helger (www.helger.com)
* philip[at]helger[dot]com
*
* Licensed 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 com.helger.photon.security.token.accesstoken;
import java.time.LocalDateTime;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.Nonempty;
import com.helger.commons.base64.Base64;
import com.helger.commons.datetime.PDTFactory;
import com.helger.commons.string.StringHelper;
import com.helger.photon.security.token.revocation.RevocationStatus;
/**
* This class represents a single token. It uniquely belongs to an application
* token or a user token. It consists of a random string token, a not-before
* date time and an optional not-after date time. Additionally it contains a
* revocation status.
*
* @author Philip Helger
*/
@NotThreadSafe
public final class AccessToken implements IAccessToken
{
private final String m_sTokenString;
private final LocalDateTime m_aNotBefore;
private LocalDateTime m_aNotAfter;
private final RevocationStatus m_aRevocationStatus;
/**
* Internal constructor for deserialization only. Use
* {@link #createNewAccessTokenValidFromNow()} or
* {@link #createAccessTokenValidFromNow(String)} instead.
*
* @param sTokenString
* The token string. May neither be null
nor empty.
* @param aNotBefore
* The date time before which the access token is invalid. May not be
* null
.
* @param aNotAfter
* The date time after which the access token is invalid. May be
* null
.
* @param aRevocationStatus
* The revocation status. May not be null
.
*/
public AccessToken (@Nonnull @Nonempty final String sTokenString,
@Nonnull final LocalDateTime aNotBefore,
@Nullable final LocalDateTime aNotAfter,
@Nonnull final RevocationStatus aRevocationStatus)
{
m_sTokenString = ValueEnforcer.notEmpty (sTokenString, "TokenString");
m_aNotBefore = ValueEnforcer.notNull (aNotBefore, "NotBefore");
if (aNotAfter != null)
setNotAfter (aNotAfter);
m_aRevocationStatus = ValueEnforcer.notNull (aRevocationStatus, "RevocationStatus");
}
@Nonnull
@Nonempty
public String getTokenString ()
{
return m_sTokenString;
}
@Nonnull
public LocalDateTime getNotBefore ()
{
return m_aNotBefore;
}
@Nullable
public LocalDateTime getNotAfter ()
{
return m_aNotAfter;
}
public void setNotAfter (@Nonnull final LocalDateTime aNotAfter)
{
ValueEnforcer.notNull (aNotAfter, "NotAfter");
if (aNotAfter.isBefore (m_aNotBefore))
throw new IllegalArgumentException ("Not after date (" +
aNotAfter +
") must be >= not before date (" +
m_aNotBefore +
")");
m_aNotAfter = aNotAfter;
}
public boolean isValidAt (@Nonnull final LocalDateTime aDT)
{
ValueEnforcer.notNull (aDT, "DateTime");
if (aDT.isBefore (m_aNotBefore))
return false;
if (m_aNotAfter != null && aDT.isAfter (m_aNotAfter))
return false;
return true;
}
@Nonnull
public RevocationStatus getRevocationStatus ()
{
return m_aRevocationStatus;
}
public void markRevoked (@Nonnull @Nonempty final String sRevocationUserID,
@Nonnull final LocalDateTime aRevocationDT,
@Nonnull @Nonempty final String sRevocationReason)
{
m_aRevocationStatus.markRevoked (sRevocationUserID, aRevocationDT, sRevocationReason);
}
/**
* @param nBytes
* The number of bytes to be used for the token. Must be > 0.
* Suggested value is 66 (dividable by 3).
* @return A newly created random token of x bytes as a Base64-encoded String.
* Never null
.
*/
@Nonnull
@Nonempty
public static String createNewTokenString (@Nonnegative final int nBytes)
{
ValueEnforcer.isGT0 (nBytes, "Bytes");
ValueEnforcer.isTrue ((nBytes % 3) == 0, "Bytes must be dividable by 3");
final byte [] aBytes = new byte [nBytes];
ThreadLocalRandom.current ().nextBytes (aBytes);
// Returns a +33% longer byte string
return Base64.encodeBytes (aBytes);
}
/**
* Create a new access token that is valid from now on for an infinite amount
* of time.
*
* @return Never null
.
*/
@Nonnull
public static AccessToken createNewAccessTokenValidFromNow ()
{
return createAccessTokenValidFromNow (null);
}
/**
* Create a new access token that is valid from now on for an infinite amount
* of time.
*
* @param sTokenString
* The existing token string. May be null
in which case a
* new token string is created.
* @return Never null
.
*/
@Nonnull
public static AccessToken createAccessTokenValidFromNow (@Nullable final String sTokenString)
{
// Length 66 so that the Base64 encoding does not add the "==" signs
// Length must be dividable by 3
final String sRealTokenString = StringHelper.hasText (sTokenString) ? sTokenString : createNewTokenString (66);
return new AccessToken (sRealTokenString,
PDTFactory.getCurrentLocalDateTime (),
null,
RevocationStatus.createUnrevoked ());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy