PublicController.java

package access.api;

import access.config.Config;
import access.manage.Manage;
import access.model.EntityType;
import lombok.SneakyThrows;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static access.manage.ManageData.getData;
import static access.manage.ManageData.getMetaDataFields;

@RestController
@RequestMapping(value = {"/api/v1/public"}, produces = MediaType.APPLICATION_JSON_VALUE)
@SuppressWarnings("unchecked")
public class PublicController {

    private static final Log LOG = LogFactory.getLog(PublicController.class);

    private final Manage manage;
    private final Config config;

    @SneakyThrows
    public PublicController(Manage manage, Config config) {
        this.manage = manage;
        this.config = config;
    }

    @GetMapping("/service-providers")
    public ResponseEntity<List<Map<String, Object>>> serviceProviders(Authentication authentication) {
        LOG.debug("/serviceProviders");
        List<Map<String, Object>> providers = manage.serviceProvidersLight();
        if (authentication == null) {
            providers.removeIf(provider -> removeNonPublicProvider(provider));
        } else {
            DefaultOidcUser user = (DefaultOidcUser) authentication.getPrincipal();
            String schacHomeOrganization = (String) user.getClaims().get("schac_home_organization");
            boolean isExternalUserFromSchacHome = schacHomeOrganization.equals(config.getEduIdSchacHomeOrganization());
            if (isExternalUserFromSchacHome) {
                providers.removeIf(provider -> removeNonPublicProvider(provider));
            } else {
                //We need the identity provider to see which providers are connected and are therefore visiblle
                String authenticatingAuthority = (String) user.getClaims().get("authenticating_authority");
                Map<String, Object> identityProvider = manage.identityProviderByEntityID(authenticatingAuthority);
                Set<String> allowedEntities = ((List<Map<String, String>>) getData(identityProvider)
                        .getOrDefault("allowedEntities", List.of()))
                        .stream()
                        .map(allowedEntity -> allowedEntity.get("name"))
                        .collect(Collectors.toSet());
                providers.removeIf(provider -> removeNonPublicProvider(provider, allowedEntities));
            }
        }
        return ResponseEntity.ok(providers);
    }

    @GetMapping("/identity-providers")
    public ResponseEntity<List<Map<String, Object>>> identityProviders() {
        LOG.debug("/identityProviders");
        return ResponseEntity.ok(manage.identityProvidersLight());
    }

    @GetMapping("/service-provider-detail/{type}/{identifier}")
    public ResponseEntity<Map<String, Object>> serviceProviderDetail(
            @PathVariable("type") EntityType entityType,
            @PathVariable("identifier") String identifier) {
        LOG.debug("/identityProviders");
        Map<String, Object> provider = manage
                .providerByManageIdentifier(entityType, identifier);
        getMetaDataFields(getData(provider)).keySet()
                .removeIf(key -> key.startsWith("contacts:"));
        return ResponseEntity.ok(provider);
    }

    private boolean removeNonPublicProvider(Map<String, Object> provider) {
        Map<String, Object> metaDataFields = getMetaDataFields(getData(provider));
        boolean hidden = (boolean) metaDataFields.getOrDefault("coin:ss:hidden", false);
        boolean idpVisibleOnly = (boolean) metaDataFields.getOrDefault("coin:ss:idp_visible_only", false);
        return hidden || idpVisibleOnly;
    }

    private boolean removeNonPublicProvider(Map<String, Object> provider, Set<String> allowedEntities) {
        Map<String, Object> data = getData(provider);
        Map<String, Object> metaDataFields = getMetaDataFields(data);
        boolean hidden = (boolean) metaDataFields.getOrDefault("coin:ss:hidden", false);
        boolean idpVisibleOnly = (boolean) metaDataFields.getOrDefault("coin:ss:idp_visible_only", false);
        return hidden || (idpVisibleOnly && !allowedEntities.contains((String) data.get("entityid")));
    }
}