Search in sources :

Example 1 with JWTDecodeException

use of com.auth0.jwt.exceptions.JWTDecodeException in project hopsworks by logicalclocks.

the class JupyterJWTManager method recover.

protected void recover() {
    LOG.log(INFO, "Starting Jupyter JWT manager recovery");
    List<MaterializedJWT> failed2recover = new ArrayList<>();
    // Get state from the database
    for (MaterializedJWT materializedJWT : materializedJWTFacade.findAll4Jupyter()) {
        LOG.log(Level.FINEST, "Recovering Jupyter JWT " + materializedJWT.getIdentifier());
        // First lookup project and user in db
        Project project = projectFacade.find(materializedJWT.getIdentifier().getProjectId());
        Users user = userFacade.find(materializedJWT.getIdentifier().getUserId());
        if (project == null || user == null) {
            LOG.log(Level.WARNING, "Tried to recover " + materializedJWT.getIdentifier() + " but could not find " + "either Project or User");
            failed2recover.add(materializedJWT);
            continue;
        }
        // Get Jupyter configuration from db
        String hdfsUsername = hdfsUsersController.getHdfsUserName(project, user);
        JupyterProject jupyterProject = jupyterFacade.findByUser(hdfsUsername);
        if (jupyterProject == null) {
            LOG.log(Level.FINEST, "There is no Jupyter configuration persisted for " + materializedJWT.getIdentifier());
            failed2recover.add(materializedJWT);
            continue;
        }
        // Check if Jupyter is still running
        if (!jupyterManager.ping(jupyterProject)) {
            LOG.log(Level.FINEST, "Jupyter server is not running for " + materializedJWT.getIdentifier() + " Skip recovering...");
            failed2recover.add(materializedJWT);
            continue;
        }
        JupyterSettings jupyterSettings = jupyterSettingsFacade.findByProjectUser(project, user.getEmail());
        Path tokenFile = constructTokenFilePath(jupyterSettings);
        String token = null;
        JupyterJWT jupyterJWT = null;
        CidAndPort pidAndPort = new CidAndPort(jupyterProject.getCid(), jupyterProject.getPort());
        try {
            token = FileUtils.readFileToString(tokenFile.toFile());
            DecodedJWT decodedJWT = jwtController.verifyToken(token, settings.getJWTIssuer());
            jupyterJWT = new JupyterJWT(project, user, DateUtils.date2LocalDateTime(decodedJWT.getExpiresAt()), pidAndPort);
            jupyterJWT.token = token;
            jupyterJWT.tokenFile = tokenFile;
            LOG.log(Level.FINE, "Successfully read existing JWT from local filesystem");
        } catch (IOException | JWTException | JWTDecodeException ex) {
            LOG.log(Level.FINE, "Could not recover Jupyter JWT from local filesystem, generating new!", ex);
            // JWT does not exist or it is not valid any longer
            // We should create a new one
            String[] audience = new String[] { "api" };
            LocalDateTime expirationDate = LocalDateTime.now().plus(settings.getJWTLifetimeMs(), ChronoUnit.MILLIS);
            String[] userRoles = usersController.getUserRoles(user).toArray(new String[1]);
            try {
                Map<String, Object> claims = new HashMap<>(3);
                claims.put(Constants.RENEWABLE, false);
                claims.put(Constants.EXPIRY_LEEWAY, settings.getJWTExpLeewaySec());
                claims.put(Constants.ROLES, userRoles);
                token = jwtController.createToken(settings.getJWTSigningKeyName(), false, settings.getJWTIssuer(), audience, DateUtils.localDateTime2Date(expirationDate), DateUtils.localDateTime2Date(DateUtils.getNow()), user.getUsername(), claims, SignatureAlgorithm.valueOf(settings.getJWTSignatureAlg()));
                jupyterJWT = new JupyterJWT(project, user, expirationDate, pidAndPort);
                jupyterJWT.token = token;
                jupyterJWT.tokenFile = tokenFile;
                jwtTokenWriter.writeToken(settings, jupyterJWT);
                LOG.log(Level.FINE, "Generated new Jupyter JWT cause could not recover existing");
            } catch (IOException recIOEx) {
                LOG.log(Level.WARNING, "Failed to recover Jupyter JWT for " + materializedJWT.getIdentifier() + ", generated new valid JWT but failed to write to local filesystem. Invalidating new token!" + " Continue recovering...");
                if (token != null) {
                    try {
                        jwtController.invalidate(token);
                    } catch (InvalidationException jwtInvEx) {
                    // NO-OP
                    }
                }
                failed2recover.add(materializedJWT);
                continue;
            } catch (GeneralSecurityException | JWTException jwtEx) {
                LOG.log(Level.WARNING, "Failed to recover Jupyter JWT for " + materializedJWT.getIdentifier() + ", tried to generate new token and it failed as well. Could not recover! Continue recovering...");
                // Did our best, it's good to know when you should give up
                failed2recover.add(materializedJWT);
                continue;
            }
        }
        addToken(jupyterJWT);
    }
    // Remove from the database entries that we failed to recover
    for (MaterializedJWT failedRecovery : failed2recover) {
        materializedJWTFacade.delete(failedRecovery.getIdentifier());
    }
    LOG.log(INFO, "Finished Jupyter JWT recovery");
}
Also used : Path(java.nio.file.Path) LocalDateTime(java.time.LocalDateTime) JWTException(io.hops.hopsworks.jwt.exception.JWTException) ArrayList(java.util.ArrayList) JupyterProject(io.hops.hopsworks.persistence.entity.jupyter.JupyterProject) Users(io.hops.hopsworks.persistence.entity.user.Users) IOException(java.io.IOException) MaterializedJWT(io.hops.hopsworks.persistence.entity.airflow.MaterializedJWT) JupyterProject(io.hops.hopsworks.persistence.entity.jupyter.JupyterProject) Project(io.hops.hopsworks.persistence.entity.project.Project) JWTDecodeException(com.auth0.jwt.exceptions.JWTDecodeException) JupyterSettings(io.hops.hopsworks.persistence.entity.jupyter.JupyterSettings) InvalidationException(io.hops.hopsworks.jwt.exception.InvalidationException) DecodedJWT(com.auth0.jwt.interfaces.DecodedJWT) Map(java.util.Map) HashMap(java.util.HashMap)

Example 2 with JWTDecodeException

use of com.auth0.jwt.exceptions.JWTDecodeException in project hopsworks by logicalclocks.

the class AirflowManager method recover.

/**
 * Recover security material for Airflow after restart. Read all active material from the database.
 * Check if JWT exists in the local filesystem and it is valid.
 * If not try to create a new one. Finally, materialize X.509 for project specific user.
 */
private void recover() {
    LOG.log(Level.FINE, "Starting Airflow manager recovery");
    List<MaterializedJWT> failed2recover = new ArrayList<>();
    Project project = null;
    Users user = null;
    // Get last known state from storage
    for (MaterializedJWT material : materializedJWTFacade.findAll4Airflow()) {
        LOG.log(Level.FINEST, "Recovering material: " + material.getIdentifier().getProjectId() + " - " + material.getIdentifier().getUserId());
        project = projectFacade.find(material.getIdentifier().getProjectId());
        user = userFacade.find(material.getIdentifier().getUserId());
        if (project == null || user == null) {
            LOG.log(Level.WARNING, "Error while recovering Project with ID: " + material.getIdentifier().getProjectId() + " and User ID: " + material.getIdentifier().getUserId() + ". Project or user is null");
            failed2recover.add(material);
            continue;
        }
        Path tokenFile = Paths.get(getProjectSecretsDirectory(user.getUsername()).toString(), getTokenFileName(project.getName(), user.getUsername()));
        AirflowJWT airflowJWT;
        String token = null;
        String materialIdentifier = "Project: " + project.getName() + " - User: " + user.getUsername();
        try {
            // First try to read JWT from the filesystem. We expect most of the cases this will succeed.
            token = FileUtils.readFileToString(tokenFile.toFile(), Charset.defaultCharset());
            DecodedJWT decoded = jwtController.verifyToken(token, settings.getJWTIssuer());
            airflowJWT = new AirflowJWT(user.getUsername(), project.getId(), project.getName(), DateUtils.date2LocalDateTime(decoded.getExpiresAt()), user.getUid());
            airflowJWT.tokenFile = tokenFile;
            airflowJWT.token = token;
            LOG.log(Level.FINE, "Successfully read existing JWT from local filesystem for " + materialIdentifier);
        } catch (IOException | JWTException | JWTDecodeException ex) {
            // JWT does not exist in the filesystem or we cannot read them or it is not valid any longer
            // We will create a new one
            // TODO(Antonis): Not very good that audience is hardcoded, but it is not accessible from hopsworks-common
            String[] audience = new String[] { "api" };
            LocalDateTime expirationDate = DateUtils.getNow().plus(settings.getJWTLifetimeMs(), ChronoUnit.MILLIS);
            String[] roles = getUserRoles(user);
            try {
                LOG.log(Level.FINEST, "JWT for " + materialIdentifier + " does not exist in the local FS or it is not " + "valid any longer, creating new one...");
                Map<String, Object> claims = new HashMap<>(3);
                claims.put(Constants.RENEWABLE, false);
                claims.put(Constants.EXPIRY_LEEWAY, settings.getJWTExpLeewaySec());
                claims.put(Constants.ROLES, roles);
                token = jwtController.createToken(settings.getJWTSigningKeyName(), false, settings.getJWTIssuer(), audience, DateUtils.localDateTime2Date(expirationDate), DateUtils.localDateTime2Date(DateUtils.getNow()), user.getUsername(), claims, SignatureAlgorithm.valueOf(settings.getJWTSignatureAlg()));
                airflowJWT = new AirflowJWT(user.getUsername(), project.getId(), project.getName(), expirationDate, user.getUid());
                airflowJWT.tokenFile = tokenFile;
                airflowJWT.token = token;
                writeTokenToFile(airflowJWT);
                LOG.log(Level.FINE, "Created new JWT for " + materialIdentifier + " and flushed to local FS");
            } catch (IOException ex1) {
                // Managed to create token but failed to write
                LOG.log(Level.WARNING, "Could not write to local FS new JWT for recovered material " + materialIdentifier + ". We will invalidate it and won't renew it.", ex1);
                if (token != null) {
                    try {
                        LOG.log(Level.FINE, "Failed to write JWT for " + materialIdentifier + ". Invalidating it...");
                        jwtController.invalidate(token);
                    } catch (InvalidationException ex2) {
                    // Not much we can do about it
                    }
                }
                failed2recover.add(material);
                continue;
            } catch (GeneralSecurityException | JWTException ex1) {
                LOG.log(Level.WARNING, "Tried to recover JWT for " + materialIdentifier + " but we failed. Giving up... " + "JWT will not be available for Airflow DAGs", ex1);
                // Initial token is invalid and could not create new. Give up
                failed2recover.add(material);
                continue;
            }
        }
        // If everything went fine with JWT, proceed with X.509
        try {
            LOG.log(Level.FINEST, "Materializing X.509 for " + materialIdentifier);
            certificateMaterializer.materializeCertificatesLocalCustomDir(user.getUsername(), project.getName(), getProjectSecretsDirectory(user.getUsername()).toString());
            LOG.log(Level.FINE, "Materialized X.509 for " + materialIdentifier);
            airflowJWTs.add(airflowJWT);
        } catch (IOException ex) {
            LOG.log(Level.WARNING, "Could not materialize X.509 for " + materialIdentifier + " Invalidating JWT and deleting from FS. JWT and X.509 will not be available for Airflow DAGs.", ex);
            // Could not materialize X.509
            if (token != null) {
                try {
                    LOG.log(Level.FINE, "Failed to materialize X.509 for " + materialIdentifier + " Invalidating JWT and deleting it from local FS.");
                    jwtController.invalidate(token);
                    FileUtils.deleteDirectory(getProjectSecretsDirectory(user.getUsername()).toFile());
                } catch (InvalidationException | IOException ex1) {
                // Not much we can do about it
                }
            }
            failed2recover.add(material);
        }
    }
    // Remove failed material from persistent storage
    for (MaterializedJWT failed : failed2recover) {
        materializedJWTFacade.delete(failed.getIdentifier());
    }
}
Also used : Path(java.nio.file.Path) LocalDateTime(java.time.LocalDateTime) JWTException(io.hops.hopsworks.jwt.exception.JWTException) ArrayList(java.util.ArrayList) Users(io.hops.hopsworks.persistence.entity.user.Users) IOException(java.io.IOException) MaterializedJWT(io.hops.hopsworks.persistence.entity.airflow.MaterializedJWT) Project(io.hops.hopsworks.persistence.entity.project.Project) JWTDecodeException(com.auth0.jwt.exceptions.JWTDecodeException) InvalidationException(io.hops.hopsworks.jwt.exception.InvalidationException) DecodedJWT(com.auth0.jwt.interfaces.DecodedJWT) Map(java.util.Map) HashMap(java.util.HashMap)

Aggregations

JWTDecodeException (com.auth0.jwt.exceptions.JWTDecodeException)2 DecodedJWT (com.auth0.jwt.interfaces.DecodedJWT)2 InvalidationException (io.hops.hopsworks.jwt.exception.InvalidationException)2 JWTException (io.hops.hopsworks.jwt.exception.JWTException)2 MaterializedJWT (io.hops.hopsworks.persistence.entity.airflow.MaterializedJWT)2 Project (io.hops.hopsworks.persistence.entity.project.Project)2 Users (io.hops.hopsworks.persistence.entity.user.Users)2 IOException (java.io.IOException)2 Path (java.nio.file.Path)2 LocalDateTime (java.time.LocalDateTime)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 JupyterProject (io.hops.hopsworks.persistence.entity.jupyter.JupyterProject)1 JupyterSettings (io.hops.hopsworks.persistence.entity.jupyter.JupyterSettings)1