001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.server.auth; 018 019import static org.apache.juneau.commons.utils.Shorts.*; 020 021import java.security.*; 022import java.util.*; 023 024/** 025 * Immutable value type returned by {@link AuthFilter#authenticate(jakarta.servlet.http.HttpServletRequest)} on success. 026 * 027 * <p> 028 * Carries the resolved {@link Principal} and the set of roles associated with the authenticated subject. 029 * The role set may be empty when no role claims are available (the principal is still valid). 030 * 031 * <h5 class='section'>See Also:</h5><ul> 032 * <li class='jc'>{@link AuthFilter} 033 * <li class='jc'>{@link AuthFilterChain} 034 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/AuthFilterFramework">AuthN Filter Framework — Servlet-Layer Authentication</a> 035 * </ul> 036 * 037 * @since 10.0.0 038 */ 039@SuppressWarnings({ 040 "java:S1192" // Duplicated "principal" literal is an assertion parameter name; a constant would obscure rather than clarify. 041}) 042public final class AuthResult { 043 044 /** 045 * Controls how an {@link AuthResult} merges with results accumulated earlier in an authenticator chain. 046 * 047 * @since 10.0.0 048 */ 049 public enum MergeMode { 050 /** Union this result's roles into the accumulated set; principal is optional (<jk>null</jk> keeps the inherited principal). */ 051 ADD, 052 /** Discard everything accumulated so far; this result's principal + roles win. Principal is required. */ 053 REPLACE 054 } 055 056 private final Principal principal; // may be null only in ADD mode 057 private final Set<String> roles; 058 private final MergeMode mode; 059 060 /** 061 * Creates an {@link AuthResult} with the specified principal and roles using {@link MergeMode#ADD} mode. 062 * 063 * @param principal The authenticated principal. Must not be <jk>null</jk>. 064 * @param roles The roles granted to this principal. May be empty. 065 * @return A new {@link AuthResult}. 066 */ 067 public static AuthResult of(Principal principal, String... roles) { 068 reqnn("principal", principal); 069 return new AuthResult(principal, toSet(roles), MergeMode.ADD); 070 } 071 072 /** 073 * Creates an {@link AuthResult} with the specified principal and role set using {@link MergeMode#ADD} mode. 074 * 075 * @param principal The authenticated principal. Must not be <jk>null</jk>. 076 * @param roles The roles granted to this principal. May be <jk>null</jk> or empty. 077 * @return A new {@link AuthResult}. 078 */ 079 public static AuthResult of(Principal principal, Set<String> roles) { 080 reqnn("principal", principal); 081 return new AuthResult(principal, toSet(roles), MergeMode.ADD); 082 } 083 084 /** 085 * Creates a roles-only {@link AuthResult} ({@link MergeMode#ADD} mode, <jk>null</jk> principal). 086 * 087 * <p> 088 * Use this to contribute additional roles without supplying a principal — the accumulated/inherited 089 * principal is kept. This replaces the need for a separate roles-only authenticator type. 090 * 091 * @param roles The roles to contribute. May be empty. 092 * @return A new {@link AuthResult}. 093 */ 094 public static AuthResult ofRoles(String... roles) { 095 return new AuthResult(null, toSet(roles), MergeMode.ADD); 096 } 097 098 /** 099 * Creates a roles-only {@link AuthResult} ({@link MergeMode#ADD} mode, <jk>null</jk> principal). 100 * 101 * @param roles The roles to contribute. May be <jk>null</jk> or empty. 102 * @return A new {@link AuthResult}. 103 */ 104 public static AuthResult ofRoles(Collection<String> roles) { 105 return new AuthResult(null, toSet(roles), MergeMode.ADD); 106 } 107 108 /** 109 * Creates an {@link AuthResult} that {@link MergeMode#REPLACE replaces} any accumulated identity and roles. 110 * 111 * @param principal The authenticated principal. Must not be <jk>null</jk>. 112 * @param roles The roles granted to this principal. May be empty. 113 * @return A new {@link AuthResult}. 114 */ 115 public static AuthResult replacing(Principal principal, String... roles) { 116 reqnn("principal", principal); 117 return new AuthResult(principal, toSet(roles), MergeMode.REPLACE); 118 } 119 120 /** 121 * Creates an {@link AuthResult} that {@link MergeMode#REPLACE replaces} any accumulated identity and roles. 122 * 123 * @param principal The authenticated principal. Must not be <jk>null</jk>. 124 * @param roles The roles granted to this principal. May be <jk>null</jk> or empty. 125 * @return A new {@link AuthResult}. 126 */ 127 public static AuthResult replacing(Principal principal, Set<String> roles) { 128 reqnn("principal", principal); 129 return new AuthResult(principal, toSet(roles), MergeMode.REPLACE); 130 } 131 132 private static Set<String> toSet(String... roles) { 133 return roles == null ? Collections.emptySet() : new HashSet<>(Arrays.asList(roles)); 134 } 135 136 private static Set<String> toSet(Collection<String> roles) { 137 return roles == null ? Collections.emptySet() : new HashSet<>(roles); 138 } 139 140 private AuthResult(Principal principal, Set<String> roles, MergeMode mode) { 141 this.principal = principal; 142 this.roles = u(roles); 143 this.mode = mode; 144 } 145 146 /** 147 * Returns the authenticated principal. 148 * 149 * @return The authenticated principal. May be <jk>null</jk> for a roles-only ({@link MergeMode#ADD}) result. 150 */ 151 public Principal getPrincipal() { 152 return principal; 153 } 154 155 /** 156 * Returns the merge mode for this result. 157 * 158 * @return The merge mode. Never <jk>null</jk>. 159 * @since 10.0.0 160 */ 161 public MergeMode getMode() { 162 return mode; 163 } 164 165 /** 166 * Returns the unmodifiable set of roles granted to this principal. 167 * 168 * @return The role set. Never <jk>null</jk>; may be empty. 169 */ 170 public Set<String> getRoles() { 171 return roles; 172 } 173}