Commit 9d0fc475 authored by Marek Drozdík's avatar Marek Drozdík
Browse files

feat: desktop app - oidc for masks service

parent a828705a
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -31,9 +31,11 @@ public class ApiService {
    public ApiService(ApiConfig apiConfig) {
        this.apiConfig = apiConfig;
        LOGGER.debug(
                "ApiEnvironmentManager initialized: landmarks local={}, external={}",
                "ApiEnvironmentManager initialized: landmarks local={}, stratus={}, masks local={}, stratus={}",
                apiConfig.getLandmarks().getUrl().getLocal(),
                apiConfig.getLandmarks().getUrl().getStratus());
                apiConfig.getLandmarks().getUrl().getStratus(),
                apiConfig.getMasks().getUrl().getLocal(),
                apiConfig.getMasks().getUrl().getStratus());
    }

    /**
@@ -64,4 +66,14 @@ public class ApiService {
        var url = apiConfig.getLandmarks().getUrl();
        return environment == ApiEnvironment.LOCAL ? url.getLocal() : url.getStratus();
    }

    /**
     * Returns the masks service URL for the current environment.
     *
     * @return masks service URL
     */
    public String getMasksServiceUrl() {
        var url = apiConfig.getMasks().getUrl();
        return environment == ApiEnvironment.LOCAL ? url.getLocal() : url.getStratus();
    }
}
+12 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ import org.springframework.stereotype.Component;
public class ApiConfig {

    private LandmarksConfig landmarks;
    private MasksConfig masks;

    /**
     * Configuration for the landmarks detection service.
@@ -30,6 +31,17 @@ public class ApiConfig {
        private UrlConfig url;
    }

    /**
     * Configuration for the masks detection service.
     *
     * @author Marek Drozdik
     */
    @Getter
    @Setter
    public static class MasksConfig {
        private UrlConfig url;
    }

    /**
     * Holds local and stratus URL variants for a service.
     *
+38 −19
Original line number Diff line number Diff line
package cz.fidentis.analyst.engines.face.impl;

import cz.fidentis.analyst.authentication.AuthService;
import cz.fidentis.analyst.authentication.exceptions.AuthException;
import cz.fidentis.analyst.data.face.Aca;
import cz.fidentis.analyst.data.face.HumanFace;
import cz.fidentis.analyst.data.mesh.MeshIO;
import cz.fidentis.analyst.data.mesh.MeshModel;
import cz.fidentis.analyst.data.shapes.Box;
import cz.fidentis.analyst.data.surfacemask.Mask3DProjection;
import cz.fidentis.analyst.data.surfacemask.MaskVariant;
import cz.fidentis.analyst.engines.face.ApiService;
import cz.fidentis.analyst.engines.face.exception.LocalResourceUnavailableException;
import cz.fidentis.analyst.engines.face.exception.RemoteServiceFailedException;
import cz.fidentis.analyst.engines.face.exception.RemoteServiceUnreachableException;
@@ -16,13 +20,17 @@ import cz.fidentis.analyst.engines.face.facemasksapi.model.FaceMask;
import cz.fidentis.analyst.engines.face.facemasksapi.model.FaceMaskVariant;
import cz.fidentis.analyst.engines.interactivemask.BoundingBoxMaskProjector;
import cz.fidentis.analyst.engines.interactivemask.BoundingBoxMaskProjectorConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.vecmath.Point2d;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Services related to the masks detection and management.
@@ -32,6 +40,8 @@ import java.util.*;
 */
public class FaceMasksServicesImpl {

    private static final Logger LOGGER = LoggerFactory.getLogger(FaceMasksServicesImpl.class);

    /**
     * Runs automatic detection of face masks for pre-defined parts of the face.
     *
@@ -127,27 +137,36 @@ public class FaceMasksServicesImpl {
        return mask3DProjections;
    }

    /**
     * Creates and configures a client for interacting with the masks detection API.
     * <p>
     * In local mode, no authentication is needed.
     * </p>
     *
     * @return A configured {@link FaceMasksApi} client for making requests to the
     *         masks detection service.
     * @throws LocalResourceUnavailableException if user is not authenticated (non-local mode only)
     */
    private FaceMasksApi getFaceMaskDetectorClient() throws LocalResourceUnavailableException {
        // Read config data from property file generated by maven
        InputStream is = getClass().getClassLoader().getResourceAsStream("my.properties");
        java.util.Properties p = new Properties();
        try {
            p.load(is);
        } catch (IOException e) {
            throw new LocalResourceUnavailableException(e);
        }
        String apiUrl = p.getProperty("fidentis.ai.masks.service.url");
        String apiKey = p.getProperty("fidentis.ai.masks.api.key");
        ApiService apiService = Aca.getInstance().getBean(ApiService.class);
        String apiUrl = apiService.getMasksServiceUrl();

        ApiClient apiClient = new ApiClient();
        apiClient.setBasePath(apiUrl);
        apiClient.setVerifyingSsl(false); // allowing self-signed certificates

        // allowing self-signed certificates
        apiClient.setVerifyingSsl(false);

        // setting authentication key
        apiClient.setApiKeyPrefix("Bearer");
        apiClient.setApiKey(apiKey);
        // Local env does not require authentication
        if (!apiService.isLocal()) {
            String accessToken;
            try {
                AuthService authService = Aca.getInstance().getBean(AuthService.class);
                accessToken = authService.getValidAccessToken();
            } catch (AuthException e) {
                LOGGER.warn("User not authenticated for mask detection: {}", e.getMessage());
                throw new LocalResourceUnavailableException("User not authenticated", e);
            }
            apiClient.setBearerToken(accessToken);
        }

        return new FaceMasksApi(apiClient);
    }
+4 −0
Original line number Diff line number Diff line
@@ -15,3 +15,7 @@ fidentis:
      url:
        local: https://localhost:8080
        stratus: https://localhost:8080
    masks:
      url:
        local: https://localhost:8000
        stratus: https://localhost:8000
+18 −1
Original line number Diff line number Diff line
package cz.fidentis.analyst.gui.task.masks;

import cz.fidentis.analyst.authentication.AuthService;
import cz.fidentis.analyst.canvas.Canvas;
import cz.fidentis.analyst.data.face.Aca;
import cz.fidentis.analyst.data.shapes.Box;
import cz.fidentis.analyst.data.shapes.CrossSection3D;
import cz.fidentis.analyst.data.surfacemask.*;
import cz.fidentis.analyst.engines.face.ApiService;
import cz.fidentis.analyst.engines.face.FaceMasksServices;
import cz.fidentis.analyst.engines.face.FaceStateServices;
import cz.fidentis.analyst.engines.face.exception.RemoteServiceException;
@@ -11,8 +14,8 @@ import cz.fidentis.analyst.engines.interactivemask.BoundingBoxMaskProjector;
import cz.fidentis.analyst.engines.interactivemask.MaskProjector;
import cz.fidentis.analyst.engines.interactivemask.MaskProjectorBack;
import cz.fidentis.analyst.engines.interactivemask.MaskProjectorConfig;
import cz.fidentis.analyst.gui.task.ControlPanelAction;
import cz.fidentis.analyst.gui.elements.RemoteServiceWorker;
import cz.fidentis.analyst.gui.task.ControlPanelAction;
import cz.fidentis.analyst.project.Task;
import cz.fidentis.analyst.rendering.Camera;

@@ -36,6 +39,9 @@ import static cz.fidentis.analyst.gui.task.masks.InteractiveMaskPanel.ACTION_PRO
public class InteractiveMaskAction extends ControlPanelAction<InteractiveMaskPanel> {
    private static final Vector3d FRONTAL_CAMERA_POSITION = new Vector3d(0, 0, BoundingBoxMaskProjector.PROJECTION_DISTANCE);

    private final AuthService authService;
    private final ApiService apiService;

    /**
     * Constructor
     * A new {@code InteractiveMaskPanel} is instantiated and added to the {@code topControlPane}
@@ -46,6 +52,8 @@ public class InteractiveMaskAction extends ControlPanelAction<InteractiveMaskPan
     */
    public InteractiveMaskAction(Canvas canvas, Task task, JTabbedPane topControlPane) {
        super(canvas, task, topControlPane);
        this.authService = Aca.getInstance().getBean(AuthService.class);
        this.apiService = Aca.getInstance().getBean(ApiService.class);
        InteractiveMaskPanel pl = new InteractiveMaskPanel(this);
        setControlPanel(pl);
        pl.getSurfaceMaskPanel1().setFaceBoundingBox(getPrimaryFace().getBoundingBox());
@@ -255,6 +263,15 @@ public class InteractiveMaskAction extends ControlPanelAction<InteractiveMaskPan
                renderScene();
                break;
            case InteractiveMaskPanel.ACTION_DETECTION_RUN:
                // Check authentication for non-local env
                if (!apiService.isLocal() && !authService.isAuthenticated()) {
                    JOptionPane.showMessageDialog(
                            getCanvas(),
                            "Please login to use automatic mask detection.",
                            "Authentication Required",
                            JOptionPane.WARNING_MESSAGE);
                    break;
                }
                updateCurrentLayerHistory();
                detectFaceMasks();
                break;
Loading