org.elasticsearch.xpack.security.authc.UserToken Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of x-pack-security Show documentation
Show all versions of x-pack-security Show documentation
Elasticsearch Expanded Pack Plugin - Security
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
package org.elasticsearch.xpack.security.authc;
import org.elasticsearch.TransportVersion;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.xcontent.ToXContentObject;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import java.io.IOException;
import java.time.DateTimeException;
import java.time.Instant;
import java.util.Base64;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
/**
* This token is a combination of a {@link Authentication} object with an expiry. This token can be
* serialized for use later. Note, if serializing this token to a entity outside of the cluster,
* care must be taken to encrypt and validate the serialized bytes or they cannot be trusted.
*
* Additionally, care must also be used when transporting these tokens as a stolen token can be
* used by an adversary to gain access. For this reason, TLS must be enabled for these tokens to
* be used.
*/
public final class UserToken implements Writeable, ToXContentObject {
private final TransportVersion version;
private final String id;
private final Authentication authentication;
private final Instant expirationTime;
private final Map metadata;
/**
* Create a new token with an autogenerated id
*/
UserToken(Authentication authentication, Instant expirationTime) {
this(TransportVersion.current(), authentication, expirationTime, Collections.emptyMap());
}
/**
* Create a new token with an autogenerated id
*/
private UserToken(TransportVersion version, Authentication authentication, Instant expirationTime, Map metadata) {
this(UUIDs.randomBase64UUID(), version, authentication, expirationTime, metadata);
}
/**
* Create a new token from an existing id
*/
UserToken(String id, TransportVersion version, Authentication authentication, Instant expirationTime, Map metadata) {
this.version = Objects.requireNonNull(version);
this.id = Objects.requireNonNull(id);
this.authentication = Objects.requireNonNull(authentication);
this.expirationTime = Objects.requireNonNull(expirationTime);
this.metadata = metadata;
}
/**
* Creates a new token based on the values from the stream
*/
UserToken(StreamInput input) throws IOException {
this.version = input.getTransportVersion();
this.id = input.readString();
this.authentication = new Authentication(input);
this.expirationTime = Instant.ofEpochSecond(input.readLong(), input.readInt());
this.metadata = input.readGenericMap();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(id);
authentication.writeTo(out);
out.writeLong(expirationTime.getEpochSecond());
out.writeInt(expirationTime.getNano());
out.writeGenericMap(metadata);
}
/**
* Get the authentication (will not be null)
*/
Authentication getAuthentication() {
return authentication;
}
/**
* Get the expiration time
*/
Instant getExpirationTime() {
return expirationTime;
}
/**
* The ID of this token
*/
public String getId() {
return id;
}
/**
* The transport version of the node this token was created on
*/
TransportVersion getTransportVersion() {
return version;
}
/**
* The metadata associated with this token
*/
public Map getMetadata() {
return metadata;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field("id", id);
builder.field("expiration_time", expirationTime.toEpochMilli());
builder.field("version", version.id());
builder.field("metadata", metadata);
try (BytesStreamOutput output = new BytesStreamOutput()) {
output.setTransportVersion(version);
authentication.writeTo(output);
builder.field("authentication", output.bytes().toBytesRef().bytes);
}
return builder.endObject();
}
static UserToken fromSourceMap(Map source) throws IllegalStateException, DateTimeException {
final String id = (String) source.get("id");
if (id == null) {
throw new IllegalStateException("user token source document does not have the \"id\" field");
}
final Long expirationEpochMilli = (Long) source.get("expiration_time");
if (expirationEpochMilli == null) {
throw new IllegalStateException("user token source document does not have the \"expiration_time\" field");
}
final Integer versionId = (Integer) source.get("version");
if (versionId == null) {
throw new IllegalStateException("user token source document does not have the \"version\" field");
}
@SuppressWarnings("unchecked")
final Map metadata = (Map) source.get("metadata");
final String authString = (String) source.get("authentication");
if (authString == null) {
throw new IllegalStateException("user token source document does not have the \"authentication\" field");
}
final TransportVersion version = TransportVersion.fromId(versionId);
try (StreamInput in = StreamInput.wrap(Base64.getDecoder().decode(authString))) {
in.setTransportVersion(version);
Authentication authentication = new Authentication(in);
return new UserToken(id, version, authentication, Instant.ofEpochMilli(expirationEpochMilli), metadata);
} catch (IOException e) {
throw new IllegalStateException("user token source document contains malformed \"authentication\" field", e);
}
}
}