com.inrupt.client.accessgrant.AccessCredential Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of inrupt-client-accessgrant Show documentation
Show all versions of inrupt-client-accessgrant Show documentation
Access Grant support for the Inrupt Client Libraries.
/*
* Copyright Inrupt Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.inrupt.client.accessgrant;
import static com.inrupt.client.accessgrant.Utils.*;
import java.net.URI;
import java.time.Instant;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** A base class for access credentials. **/
public class AccessCredential {
private static final Logger LOGGER = LoggerFactory.getLogger(AccessCredential.class);
protected static final String TYPE = "type";
protected static final String REVOCATION_LIST_2020_STATUS = "RevocationList2020Status";
private final String credential;
private final URI issuer;
private final URI identifier;
private final Set types;
private final Set modes;
private final Set purposes;
private final Set resources;
private final URI recipient;
private final URI creator;
private final Instant expiration;
private final Instant issuedAt;
private final Status status;
/**
* Create a base class for credential types.
* @param identifier the credential identifier
* @param credential the full credential
* @param data items pertaining to user-defined credential data
* @param metadata items pertaining to server-managed credential data
*/
protected AccessCredential(final URI identifier, final String credential,
final CredentialData data, final CredentialMetadata metadata) {
this.identifier = Objects.requireNonNull(identifier, "identifier may not be null").normalize();
this.credential = Objects.requireNonNull(credential, "credential may not be null!");
Objects.requireNonNull(data, "credential data may not be null!");
Objects.requireNonNull(metadata, "credential metadata may not be null!");
this.purposes = data.getPurposes();
this.resources = data.getResources();
this.modes = data.getModes();
this.recipient = data.getRecipient();
this.issuer = metadata.getIssuer();
this.creator = metadata.getCreator();
this.types = metadata.getTypes();
this.status = metadata.getStatus();
this.expiration = metadata.getExpiration();
this.issuedAt = metadata.getIssuedAt();
}
/**
* Get the types of the access credential.
*
* @return the access credential types
*/
public Set getTypes() {
return types;
}
/**
* Get the access modes of the access credential.
*
* @return the access credential types
*/
public Set getModes() {
return modes;
}
/**
* Get the revocation status of the access credential.
*
* @return the revocation status, if present
*/
public Optional getStatus() {
return Optional.ofNullable(status);
}
/**
* Get the expiration time of the access credential.
*
* @return the expiration time
*/
public Instant getExpiration() {
return expiration != null ? expiration : Instant.MAX;
}
/**
* Get the issuance date for the credential.
*
* @return the issuance date
*/
public Instant getIssuedAt() {
return issuedAt;
}
/**
* Get the issuer of the access credential.
*
* @return the issuer
*/
public URI getIssuer() {
return issuer;
}
/**
* Get the identifier of the access credential.
*
* @return the identifier
*/
public URI getIdentifier() {
return identifier;
}
/**
* Get the collection of purposes associated with the access credential.
*
* @implNote as of Beta3, this method returns a set of URIs. Any non-URI purpose values encountered
* during access credential parsing will be discarded.
* @return the purposes
*/
public Set getPurposes() {
return purposes;
}
/**
* Get the resources associated with the access credential.
*
* @return the associated resource identifiers
*/
public Set getResources() {
return resources;
}
/**
* Get the creator of this access credential.
*
* @return the creator
*/
public URI getCreator() {
return creator;
}
/**
* Get the recipient of this access credential.
*
* @return the recipient, if present
*/
public Optional getRecipient() {
return Optional.ofNullable(recipient);
}
/**
* Serialize this access credential as a String.
*
* @return a serialized form of the credential
*/
public String serialize() {
return credential;
}
/** Server-managed credential data. */
public static class CredentialMetadata {
private final URI issuer;
private final URI creator;
private final Set types;
private final Status status;
private final Instant expiration;
private final Instant issuedAt;
/**
* A collection of server-managed credential metadata.
*
* @param issuer the issuer
* @param creator the agent who created the credential
* @param types the credential types
* @param issuedAt the credential issuance date
* @param expiration the credential expiration date
* @param status the credential status
*/
public CredentialMetadata(final URI issuer, final URI creator, final Set types,
final Instant issuedAt, final Instant expiration, final Status status) {
this.issuer = Objects.requireNonNull(issuer, "issuer may not be null!");
this.creator = Objects.requireNonNull(creator, "creator may not be null!");
this.types = Objects.requireNonNull(types, "types may not be null!");
this.issuedAt = Objects.requireNonNull(issuedAt, "issuedAt may not be null!");
this.expiration = expiration;
this.status = status;
}
/**
* Get the issuer of the credential.
*
* @return the issuer
*/
public URI getIssuer() {
return issuer;
}
/**
* Get the creator of the credential.
*
* @return the creator
*/
public URI getCreator() {
return creator;
}
/**
* Get the types of the credential.
*
* @return the credential types
*/
public Set getTypes() {
return types;
}
/**
* Get the expiration time of the credential.
*
* @return the expiration time
*/
public Instant getExpiration() {
return expiration;
}
/**
* Get the status of the credential.
*
* @return the credential status
*/
public Status getStatus() {
return status;
}
/**
* Get the instant when the credential was issued.
*
* @return the time at which the access credentials was issued
*/
public Instant getIssuedAt() {
return issuedAt;
}
}
/** User-managed credential data. */
public static class CredentialData {
private final Set modes;
private final Set purposes;
private final Set resources;
private final URI recipient;
private final URI accessRequest;
/**
* Create a collection of user-managed credential data.
*
* @param resources the resources referenced by the credential
* @param modes the access modes defined by this credential
* @param purposes the purposes associated with this credential
* @param recipient the recipient for this credential, may be {@code null}
*/
public CredentialData(final Set resources, final Set modes,
final Set purposes, final URI recipient) {
this(resources, modes, purposes, recipient, null);
}
/**
* Create a collection of user-managed credential data.
*
* @param resources the resources referenced by the credential
* @param modes the access modes defined by this credential
* @param purposes the purposes associated with this credential
* @param recipient the recipient for this credential, may be {@code null}
* @param accessRequest the access request identifier, may be {@code null}
*/
public CredentialData(final Set resources, final Set modes,
final Set purposes, final URI recipient, final URI accessRequest) {
this.modes = Objects.requireNonNull(modes, "modes may not be null!");
this.purposes = Objects.requireNonNull(purposes, "purposes may not be null!");
this.resources = Objects.requireNonNull(resources, "resources may not be null!");
this.recipient = recipient;
this.accessRequest = accessRequest;
}
/**
* Get the purposes associated with the credential.
*
* @return the purpose definitions
*/
public Set getPurposes() {
return purposes;
}
/**
* Get the access modes associated with the credential.
*
* @return the access modes
*/
public Set getModes() {
return modes;
}
/**
* Get the resource URIs associated with this credential.
*
* @return the resource URIs
*/
public Set getResources() {
return resources;
}
/**
* Get the recipient associated with this credential.
*
* @return the credential, may be {@code null}
*/
public URI getRecipient() {
return recipient;
}
/**
* Get the access request identifier associated with this credential.
*
* @return the access request identifier, may be {@code null}
*/
public URI getAccessRequest() {
return accessRequest;
}
}
static CredentialMetadata extractMetadata(final Map data) {
final URI issuer = asUri(data.get("issuer")).orElseThrow(() ->
new IllegalArgumentException("Missing or invalid issuer field"));
final Set types = asSet(data.get(TYPE)).orElseGet(Collections::emptySet);
final Instant expiration = asInstant(data.get("expirationDate")).orElse(Instant.MAX);
final Instant issuedAt = asInstant(data.get("issuanceDate")).orElse(Instant.EPOCH);
final Status status = asMap(data.get("credentialStatus")).flatMap(credentialStatus ->
asSet(credentialStatus.get(TYPE)).filter(statusTypes ->
statusTypes.contains(REVOCATION_LIST_2020_STATUS)).map(x ->
asRevocationList2020(credentialStatus))).orElse(null);
final Map subject = asMap(data.get("credentialSubject")).orElseThrow(() ->
new IllegalArgumentException("Missing or invalid credentialSubject field"));
final URI creator = asUri(subject.get("id")).orElseThrow(() ->
new IllegalArgumentException("Missing or invalid credentialSubject.id field"));
return new CredentialMetadata(issuer, creator, types, issuedAt, expiration, status);
}
static Map extractConsent(final Map data, final String property) {
final Map subject = asMap(data.get("credentialSubject")).orElseThrow(() ->
new IllegalArgumentException("Missing or invalid credentialSubject field"));
return asMap(subject.get(property)).orElseThrow(() ->
// Unsupported structure
new IllegalArgumentException("Invalid Access Request: missing consent clause"));
}
static Stream filterUris(final String uri) {
try {
return Stream.of(URI.create(uri));
} catch (final IllegalArgumentException ex) {
LOGGER.debug("Ignoring non-URI purpose: {}", ex.getMessage());
}
return Stream.empty();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy