Skip to content

Commit

Permalink
webdav/frontend/srm/gplazma: log OIDC 'sub' and 'jti' claims
Browse files Browse the repository at this point in the history
Motivation:

The 'sub' claim identifies an individual, the 'jti' claim identifies a
specific (access) token.  Both provide useful information when
diagnosing problems or providing an audit trail.

Modification:

Update access log file to log the 'sub' and 'jti' values, if either are
known.

Result:

The OIDC 'sub' (subject) and 'jti' (JWT ID) claims in the access log
file for WebDAV, frontend and SRM doors if OIDC is used.

Target: master
Request: 8.0
Request: 7.2
Requires-notes: yes
Requires-book: no
Closes: #6452
Patch: https://rb.dcache.org/r/13418/
Acked-by: Tigran Mkrtchyan
  • Loading branch information
paulmillar committed Feb 25, 2022
1 parent 025f579 commit e9cc80f
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*
* @since 5.1
*/
@AuthenticationOutput
public class JwtJtiPrincipal extends OpScopedPrincipal {

private static final long serialVersionUID = 1L;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public abstract class OpScopedPrincipal implements Principal, Serializable {
private final String name;

public OpScopedPrincipal(String op, String sub) {
name = op + ":" + sub;
name = sub + "@" + op;
}

@Override
Expand Down
17 changes: 17 additions & 0 deletions modules/common/src/main/java/org/dcache/auth/Subjects.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosPrincipal;
import org.dcache.util.PrincipalSetMaker;
Expand Down Expand Up @@ -324,6 +325,22 @@ public static String getDisplayName(Subject subject) {
return UNKNOWN;
}

/**
* Return a comma-separated list of principals names. A null value is
* returned if the Subject has no principals of this type.
* @param <T> The kind of principal to examine.
* @param subject The subject to examine.
* @param type The kind of principals to examine.
* @return A list of principal names of this type.
*/
@Nullable
public static <T extends Principal> String getPrincipalNames(Subject subject, Class<T> type) {
Set<? extends Principal> p = subject.getPrincipals(type);
return p.isEmpty()
? null
: p.stream().map(Principal::getName).collect(Collectors.joining(","));
}

/**
* Returns the "Kerberos principal" for the user (as specified in Section 2.1 of RFC 1964) if
* they logged in via Kerberos or null if Kerberos was not used.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.dcache.auth.JwtJtiPrincipal;
import org.dcache.auth.OidcSubjectPrincipal;
import org.dcache.auth.Subjects;
import org.dcache.auth.attributes.LoginAttribute;
import org.dcache.cells.CellStub;
import org.dcache.cells.CuratorFrameworkAware;
Expand Down Expand Up @@ -913,6 +916,8 @@ public void response(String requestName, Object request, Object response, Subjec
log.add("socket.remote", Axis.getRemoteSocketAddress());
log.add("request.method", requestName);
log.add("user.dn", Axis.getDN().orElse(null));
log.add("user.sub", Subjects.getPrincipalNames(user, OidcSubjectPrincipal.class));
log.add("user.jti", Subjects.getPrincipalNames(user, JwtJtiPrincipal.class));
if (user != null) {
log.add("user.mapped", user);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@
import java.net.InetSocketAddress;
import java.time.Instant;
import javax.security.auth.Subject;
import org.dcache.auth.JwtJtiPrincipal;
import org.dcache.auth.LoginReply;
import org.dcache.auth.OidcSubjectPrincipal;
import org.dcache.auth.Subjects;
import org.dcache.util.NetLoggerBuilder;
import org.dcache.xrootd.door.LoginEvent;
Expand Down Expand Up @@ -160,6 +162,8 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc
"org.dcache.xrootd.login").omitNullValues();
log.add("session", CDC.getSession());
log.add("user.dn", Subjects.getDn(subject));
log.add("user.sub", Subjects.getPrincipalNames(subject, OidcSubjectPrincipal.class));
log.add("user.jti", Subjects.getPrincipalNames(subject, JwtJtiPrincipal.class));
log.add("user.mapped", subject);
log.toLogger(logger);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dcache.auth.JwtJtiPrincipal;
import org.dcache.auth.OidcSubjectPrincipal;
import org.dcache.auth.Subjects;
import org.dcache.util.NetLoggerBuilder;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Request;
Expand Down Expand Up @@ -139,7 +142,14 @@ protected void describeOperation(NetLoggerBuilder log,
log.add("user-agent", request.getHeader("User-Agent"));

log.add("user.dn", getCertificateName(request));
log.add("user.mapped", getSubject(request));
var subject = getSubject(request);
log.add("user.sub", subject
.flatMap(s -> Optional.ofNullable(Subjects.getPrincipalNames(s, OidcSubjectPrincipal.class)))
.orElse(null));
log.add("user.jti", subject
.flatMap(s -> Optional.ofNullable(Subjects.getPrincipalNames(s, JwtJtiPrincipal.class)))
.orElse(null));
log.add("user.mapped", subject.orElse(null));
}

/**
Expand Down Expand Up @@ -199,8 +209,8 @@ private static String getCertificateName(HttpServletRequest request) {
return null;
}

private static Subject getSubject(HttpServletRequest request) {
private static Optional<Subject> getSubject(HttpServletRequest request) {
Object object = request.getAttribute(DCACHE_SUBJECT_ATTRIBUTE);
return (object instanceof Subject) ? (Subject) object : null;
return Optional.ofNullable((object instanceof Subject) ? (Subject) object : null);
}
}

0 comments on commit e9cc80f

Please sign in to comment.