// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.api.role;

import java.security.Principal;
import java.time.Instant;
import java.util.Objects;
import java.util.Set;

/**
 * @author tokle
 */
public class SecurityContext {

    public static final String ATTRIBUTE_NAME = SecurityContext.class.getName();

    private final Principal principal;
    private final Set<Role> roles;
    private final Instant issuedAt;

    public SecurityContext(Principal principal, Set<Role> roles, Instant issuedAt) {
        this.principal = Objects.requireNonNull(principal);
        this.roles = Set.copyOf(roles);
        this.issuedAt = Objects.requireNonNull(issuedAt);
    }

    public SecurityContext(Principal principal, Set<Role> roles) {
        this(principal, roles, Instant.EPOCH);
    }

    public Principal principal() {
        return principal;
    }

    public Set<Role> roles() {
        return roles;
    }

    public Instant issuedAt() {
        return issuedAt;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SecurityContext that = (SecurityContext) o;
        return Objects.equals(principal, that.principal) &&
               Objects.equals(roles, that.roles) &&
               Objects.equals(issuedAt, that.issuedAt);
    }

    @Override
    public int hashCode() {
        return Objects.hash(principal, roles, issuedAt);
    }

    @Override
    public String toString() {
        return "SecurityContext{" +
               "principal=" + principal +
               ", roles=" + roles +
               ", issuedAt=" + issuedAt +
               '}';
    }

}

@@ -506,16 +506,53 @@
 ssuedAt;
+%0A    private final Instant expiresAt;
 %0A%0A    pu
@@ -626,24 +626,190 @@
 issuedAt) %7B%0A
+        this(principal, roles, issuedAt, Instant.MAX);%0A    %7D%0A%0A    public SecurityContext(Principal principal, Set%3CRole%3E roles, Instant issuedAt, Instant expiresAt) %7B%0A
         this
@@ -946,32 +946,92 @@
 Null(issuedAt);%0A
+        this.expiresAt = Objects.requireNonNull(expiresAt);%0A
     %7D%0A%0A    publi
@@ -1132,16 +1132,29 @@
 nt.EPOCH
+, Instant.MAX
 );%0A    %7D
@@ -1339,32 +1339,167 @@
 ssuedAt;%0A    %7D%0A%0A
+    /** @return credential expiration or %7B@link Instant#MAX%7D is not available */%0A    public Instant expiresAt() %7B return expiresAt; %7D%0A%0A
     @Override%0A  
@@ -1744,39 +1744,24 @@
 rincipal) &&
-%0A              
  Objects.equ
@@ -1782,19 +1782,16 @@
 t.roles)
- &&
 %0A       
@@ -1797,16 +1797,20 @@
         
+  &&
  Objects
@@ -1833,32 +1833,77 @@
 , that.issuedAt)
+ && Objects.equals(expiresAt, that.expiresAt)
 ;%0A    %7D%0A%0A    @Ov
@@ -1987,24 +1987,35 @@
 es, issuedAt
+, expiresAt
 );%0A    %7D%0A%0A  
@@ -2108,16 +2108,17 @@
         
+ 
 %22princip
@@ -2136,16 +2136,17 @@
 cipal +%0A
+ 
         
@@ -2188,16 +2188,17 @@
         
+ 
 %22, issue
@@ -2216,16 +2216,62 @@
 uedAt +%0A
+                %22, expiresAt=%22 + expiresAt +%0A 
         

Add expiry to SecurityContext