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 java.security.*; 020 021import org.apache.juneau.commons.reflect.*; 022import org.apache.juneau.rest.server.*; 023import org.apache.juneau.rest.server.arg.*; 024 025/** 026 * Resolves {@code @RestOp}-method parameters that represent the authenticated {@link Principal}. 027 * 028 * <p> 029 * Matches any of: 030 * <ul> 031 * <li>Parameter annotated with {@link Auth} (any type). 032 * <li>Parameter typed as {@link Principal} or any subtype (including {@link ClaimsPrincipal}). 033 * </ul> 034 * 035 * <p> 036 * Resolution pulls the {@link Principal} stashed by an upstream AuthN guard 037 * ({@link BearerTokenGuard} / {@link ApiKeyGuard}) on the request attributes under 038 * {@code "juneau.principal"}. If the stashed value is missing or not assignable to 039 * the requested parameter type, <jk>null</jk> is injected — the guard chain is the contract 040 * that guarantees a non-null value. 041 * 042 * <p> 043 * Type-driven resolution lets a bare {@code Principal} parameter be filled without an annotation, 044 * matching the Spring / Servlet convention; the {@link Auth} annotation is for clarity and for 045 * disambiguating against another arg resolver that might otherwise claim the parameter. 046 * 047 * <h5 class='section'>See Also:</h5><ul> 048 * <li class='jc'>{@link Auth} 049 * <li class='jc'>{@link BearerTokenGuard} 050 * <li class='jc'>{@link ApiKeyGuard} 051 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerAuthGuards">AuthN Guards — Bearer / API-Key / JWT</a> 052 * </ul> 053 * 054 * @since 10.0.0 055 */ 056public class AuthArg implements RestOpArg { 057 058 private static final AnnotationProvider AP = AnnotationProvider.INSTANCE; 059 060 /** 061 * Static creator. 062 * 063 * @param paramInfo The Java method parameter being resolved. Must not be <jk>null</jk>. 064 * @return A new {@link AuthArg}, or <jk>null</jk> if the parameter is not eligible. 065 */ 066 public static AuthArg create(ParameterInfo paramInfo) { 067 var hasAuth = AP.has(Auth.class, paramInfo); 068 var isPrincipal = paramInfo.getParameterType().isAssignableTo(Principal.class); 069 if (hasAuth || isPrincipal) 070 return new AuthArg(paramInfo); 071 return null; 072 } 073 074 private final Class<?> type; 075 076 /** 077 * Constructor. 078 * 079 * @param paramInfo The Java method parameter being resolved. Must not be <jk>null</jk>. 080 */ 081 protected AuthArg(ParameterInfo paramInfo) { 082 this.type = paramInfo.getParameterType().inner(); 083 } 084 085 @Override /* Overridden from RestOpArg */ 086 public Object resolve(RestOpSession opSession) { 087 var v = opSession.getRequest().getAttribute("juneau.principal").getValue(); 088 if (v == null || ! type.isInstance(v)) 089 return null; 090 return v; 091 } 092}