LocalDevelopmentAuthenticationFilter.java

package access.security;

import access.model.Institution;
import jakarta.servlet.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;

import java.io.IOException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import static access.security.InstitutionAdmin.IDENTITY_PROVIDER;
import static access.security.InstitutionAdmin.INSTITUTION;

public class LocalDevelopmentAuthenticationFilter implements Filter {

    //private static final String sub = "urn:collab:person:example.com:mos";
    private static final String sub = "urn:collab:person:example.com:admin";
    private static final String schacHomeOrganization = "example.com";

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            LocalDevelopmentAuthenticationFilter.populateSecurityContext(Map.of());
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @SuppressWarnings("unchecked")
    public static void populateSecurityContext(Map<String, Object> body) {
        List<SimpleGrantedAuthority> authorities = List.of(new SimpleGrantedAuthority("OPENID"));
        Map<String, Object> defaultClaims = Map.of(
                "eduperson_principal_name", "urn:collab:person:example.com:super",
                "email", "jdoe@example.com",
                "family_name", "Doe",
                "authenticating_authority", "http://mock-idp",
                "given_name", "John",
                "name", "John Doe",
                "schac_home_organization", schacHomeOrganization,
                "scope", "openid",
                "sub", body.getOrDefault("sub", LocalDevelopmentAuthenticationFilter.sub),
                "uids", List.of("super"));
        //We can't rely on the mutability of the body
        Map<String, Object> claims = new HashMap<>(defaultClaims);
        if (body.containsKey(IDENTITY_PROVIDER)) {
            body.put(INSTITUTION, new Institution((Map<String, Object>) body.get(IDENTITY_PROVIDER)));
            body.remove(IDENTITY_PROVIDER);
        }
        claims.putAll(body);

        OidcIdToken idToken = new OidcIdToken(
                UUID.randomUUID().toString(),
                Instant.now(),
                Instant.now().plus(1, ChronoUnit.HOURS),
                claims
        );
        OidcUserInfo userInfo = new OidcUserInfo(claims);
        DefaultOidcUser oidcUser = new DefaultOidcUser(authorities, idToken, userInfo);
        OAuth2AuthenticationToken authenticationToken = new OAuth2AuthenticationToken(
                oidcUser,
                authorities,
                "oidcng"
        );
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    }
}