org.soulwing.jwt.api.BiPredicateAssertions Maven / Gradle / Ivy
/*
* File created on Mar 8, 2019
*
* Copyright (c) 2019 Carl Harris, Jr
* and others as noted
*
* 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 org.soulwing.jwt.api;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* An {@link Assertions} implementation that evaluates a list of
* {@link BiPredicate} lambdas.
*
* @author Carl Harris
*/
public final class BiPredicateAssertions implements Assertions {
private final List> assertions = new ArrayList<>();
private void addClaimAssertion(Function> accessor,
Predicate condition) {
assertions.add((claims, clock) ->
accessor.apply(claims).map(condition::test).orElse(false));
}
private void addClaimAssertion(Function> accessor,
BiPredicate condition) {
assertions.add((claims, clock) ->
accessor.apply(claims)
.map(v -> condition.test(v, clock))
.orElse(false));
}
public static final class Builder implements Assertions.Builder {
private final BiPredicateAssertions assertions;
Builder(BiPredicateAssertions assertions) {
this.assertions = assertions;
}
@Override
public Assertions.Builder requireId() {
return requireIdSatisfies(v -> v != null && !v.trim().isEmpty());
}
@Override
public Assertions.Builder requireIdSatisfies(Predicate condition) {
return requireSatisfies(Claims.JTI, String.class, condition);
}
@Override
public Assertions.Builder requireLifetimeNotExceeded(Duration lifetime) {
return requireIssuedAtSatisfies((t, clock) ->
clock.instant().minus(lifetime).isBefore(t));
}
@Override
public Assertions.Builder requireIssuedAtSatisfies(
BiPredicate condition) {
return requireInstantSatisfies(Claims.IAT, condition);
}
@Override
public Assertions.Builder requireNotExpired(Duration tolerance) {
return requireExpirationSatisfies((t, clock) ->
clock.instant().minus(tolerance).isBefore(t));
}
@Override
public Assertions.Builder requireExpirationSatisfies(
BiPredicate condition) {
return requireInstantSatisfies(Claims.EXP, condition);
}
@Override
public Assertions.Builder requireIssuer(String issuer, String... otherIssuers) {
return requireEquals(Claims.ISS, issuer, (Object[]) otherIssuers);
}
@Override
public Assertions.Builder requireIssuerSatisfies(Predicate condition) {
return requireSatisfies(Claims.ISS, String.class, condition);
}
@Override
public Assertions.Builder requireAudience(String audience,
String... otherAudiences) {
return requireContains(Claims.AUD, audience, (Object[]) otherAudiences);
}
@Override
public Assertions.Builder requireAudienceSatisfies(Predicate condition) {
assertions.addClaimAssertion(listAccessor(Claims.AUD), condition);
return this;
}
@Override
public Assertions.Builder requireSubject(String subject, String... otherSubjects) {
return requireEquals(Claims.SUB, subject, (Object[]) otherSubjects);
}
@Override
public Assertions.Builder requireSubjectSatisfies(Predicate condition) {
return requireSatisfies(Claims.SUB, String.class, condition);
}
@Override
public Assertions.Builder requireEquals(
String name, Object value, Object... otherValues) {
return requireSatisfies(name, Object.class,
v -> v.equals(value) || Arrays.asList(otherValues).contains(v));
}
@Override
public Assertions.Builder requireContains(
String name, Object value, Object... otherValues) {
assertions.addClaimAssertion(listAccessor(name),
v -> v != null
&& (v.contains(value)
|| Arrays.stream(otherValues).anyMatch(v::contains)));
return this;
}
@Override
@SuppressWarnings("unchecked")
public final Assertions.Builder requireSatisfies(
String name, Class extends T> type, Predicate condition) {
assertions.addClaimAssertion(valueAccessor(name),
(v) -> type.isInstance(v) && condition.test((T) v));
return this;
}
@Override
public final Assertions.Builder requireInstantSatisfies(
String name, BiPredicate condition) {
assertions.addClaimAssertion(valueAccessor(name),
(v, clock) -> v instanceof Number
&& condition.test(
Instant.ofEpochSecond(((Number) v).longValue()), clock));
return this;
}
private Function> valueAccessor(String name) {
return (claims) -> claims.claim(name, Object.class);
}
private Function> listAccessor(String name) {
return (claims) ->
claims.claim(name, Object.class)
.map(v -> v instanceof List ?
(List) v : Collections.singletonList(v));
}
@Override
public BiPredicateAssertions build() {
return assertions;
}
}
/**
* Gets a builder for a new instance.
* @return builder
*/
public static Builder builder() {
return new Builder(new BiPredicateAssertions());
}
@Override
public boolean test(Claims claims, Clock clock) {
return assertions.stream()
.allMatch(assertion -> assertion.test(claims, clock));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy