<commit_before>package mil.dds.anet.auth;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import io.dropwizard.auth.Authorizer;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.security.Principal;
import java.util.List;
import javax.annotation.Priority;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.SecurityContext;
import mil.dds.anet.AnetObjectEngine;
import mil.dds.anet.beans.Person;
import mil.dds.anet.beans.Person.Role;
import mil.dds.anet.beans.Position;
import mil.dds.anet.beans.Position.PositionType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Priority(1500) // Run After Authentication, but before Authorization
public class AnetAuthenticationFilter implements ContainerRequestFilter, Authorizer<Person> {

  private static final Logger logger =
      LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

  private final AnetObjectEngine engine;
  private final Timer timerFilter;
  private final Timer timerAuthorize;

  public AnetAuthenticationFilter(AnetObjectEngine engine, MetricRegistry metricRegistry) {
    this.engine = engine;
    this.timerFilter = metricRegistry.timer(MetricRegistry.name(this.getClass(), "filter"));
    this.timerAuthorize = metricRegistry.timer(MetricRegistry.name(this.getClass(), "authorize"));
  }

  @Override
  public void filter(ContainerRequestContext ctx) throws IOException {
    final Timer.Context context = timerFilter.time();
    try {
      final SecurityContext secContext = ctx.getSecurityContext();
      Principal p = secContext.getUserPrincipal();
      if (p != null) {
        String domainUsername = p.getName();
        List<Person> matches = engine.getPersonDao().findByDomainUsername(domainUsername);
        Person person;
        if (matches.size() == 0) {
          // First time this user has ever logged in.
          person = new Person();
          person.setDomainUsername(domainUsername);
          person.setName("");
          person.setRole(Role.ADVISOR);
          person.setPendingVerification(true);
          person = engine.getPersonDao().insert(person);
        } else {
          person = matches.get(0);
        }

        final Person user = person;
        ctx.setSecurityContext(new SecurityContext() {
          @Override
          public Principal getUserPrincipal() {
            return user;
          }

          @Override
          public boolean isUserInRole(String role) {
            return authorize(user, role);
          }

          @Override
          public boolean isSecure() {
            return secContext.isSecure();
          }

          @Override
          public String getAuthenticationScheme() {
            return secContext.getAuthenticationScheme();
          }
        });
      } else {
        throw new WebApplicationException("Unauthorized", Status.UNAUTHORIZED);
      }
    } finally {
      context.stop();
    }
  }

  @Override
  public boolean authorize(Person principal, String role) {
    final Timer.Context context = timerAuthorize.time();
    try {
      return checkAuthorization(principal, role);
    } finally {
      context.stop();<commit_msg>NCI-Agency/anet#3491: Avoid creating multiple new users<commit_after>package mil.dds.anet.auth;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import io.dropwizard.auth.Authorizer;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.security.Principal;
import java.util.List;
import javax.annotation.Priority;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.SecurityContext;
import mil.dds.anet.AnetObjectEngine;
import mil.dds.anet.beans.Person;
import mil.dds.anet.beans.Person.Role;
import mil.dds.anet.beans.Position;
import mil.dds.anet.beans.Position.PositionType;
import mil.dds.anet.database.PersonDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Priority(1500) // Run After Authentication, but before Authorization
public class AnetAuthenticationFilter implements ContainerRequestFilter, Authorizer<Person> {

  private static final Logger logger =
      LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

  private final PersonDao dao;
  private final Timer timerFilter;
  private final Timer timerAuthorize;

  public AnetAuthenticationFilter(AnetObjectEngine engine, MetricRegistry metricRegistry) {
    this.dao = engine.getPersonDao();
    this.timerFilter = metricRegistry.timer(MetricRegistry.name(this.getClass(), "filter"));
    this.timerAuthorize = metricRegistry.timer(MetricRegistry.name(this.getClass(), "authorize"));
  }

  @Override
  public void filter(ContainerRequestContext ctx) throws IOException {
    final Timer.Context context = timerFilter.time();
    try {
      final SecurityContext secContext = ctx.getSecurityContext();
      final Principal p = secContext.getUserPrincipal();
      if (p != null) {
        // Call non-synchronized method first
        Person person = findUser(p);
        if (person == null) {
          // Call synchronized method
          person = findOrCreateUser(p);
        }

        final Person user = person;
        ctx.setSecurityContext(new SecurityContext() {
          @Override
          public Principal getUserPrincipal() {
            return user;
          }

          @Override
          public boolean isUserInRole(String role) {
            return authorize(user, role);
          }

          @Override
          public boolean isSecure() {
            return secContext.isSecure();
          }

          @Override
          public String getAuthenticationScheme() {
            return secContext.getAuthenticationScheme();
          }
        });
      } else {
        throw new WebApplicationException("Unauthorized", Status.UNAUTHORIZED);
      }
    } finally {
      context.stop();
    }
  }

  // Non-synchronized method, safe to run multiple times in parallel
  private Person findUser(Principal p) {
    final String domainUsername = p.getName();
    final List<Person> matches = dao.findByDomainUsername(domainUsername);
    return (matches.size() == 0) ? null : matches.get(0);
  }

  // Synchronized method, so we create at most one user in the face of multiple simultaneous
  // authentication requests
  private synchronized Person findOrCreateUser(Principal p) {
    final Person person = findUser(p);
    if (person != null) {
      return person;
    }
    // First time this user has ever logged in.
    final Person newPerson = new Person();
    final String domainUsername = p.getName();
    newPerson.setDomainUsername(domainUsername);
    newPerson.setName("");
    newPerson.setRole(Role.ADVISOR);
    newPerson.setPendingVerification(true);
    return dao.insert(newPerson);
  }

  @Override
  public boolean authorize(Person principal, String role) {
    final Timer.Context context = timerAuthorize.time();
    try {
      return checkAuthorization(principal, role);
    } finally {
      context.stop();
{'fraction_non_alphanumeric': 0.09714441863642574, 'fraction_numerical': 0.0027326137450471378, 'mean_word_length': 3.250871080139373, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6814888', 'n_tokens_mistral': 1994, 'n_tokens_neox': 1956, 'n_words': 461}