diff --git a/hopsworks-IT/src/test/ruby/spec/jwt_spec.rb b/hopsworks-IT/src/test/ruby/spec/jwt_spec.rb index 69fac4c356..0fe3b0c28a 100644 --- a/hopsworks-IT/src/test/ruby/spec/jwt_spec.rb +++ b/hopsworks-IT/src/test/ruby/spec/jwt_spec.rb @@ -44,8 +44,6 @@ expect_status_details(200) expect(headers["authorization"]).not_to be_nil expect(headers["authorization"]).not_to be_empty - renew_tokens = json_body[:renewTokens] - expect(renew_tokens.length).to eql(5) end describe "#logged in as service user" do @@ -57,7 +55,6 @@ post "#{ENV['HOPSWORKS_API']}/auth/service", URI.encode_www_form({ email: "agent@hops.io", password: "admin"}), { content_type: 'application/x-www-form-urlencoded'} - @renew_tokens = json_body[:renewTokens] @master_token = headers["authorization"].split[1].strip end diff --git a/hopsworks-api/src/main/java/io/hops/hopsworks/api/user/AuthService.java b/hopsworks-api/src/main/java/io/hops/hopsworks/api/user/AuthService.java index 09c1b1743c..404aaf16bf 100644 --- a/hopsworks-api/src/main/java/io/hops/hopsworks/api/user/AuthService.java +++ b/hopsworks-api/src/main/java/io/hops/hopsworks/api/user/AuthService.java @@ -52,13 +52,11 @@ import io.hops.hopsworks.common.user.AuthController; import io.hops.hopsworks.common.user.QrCode; import io.hops.hopsworks.common.user.UsersController; -import io.hops.hopsworks.common.util.DateUtils; import io.hops.hopsworks.common.util.Settings; import io.hops.hopsworks.exceptions.HopsSecurityException; import io.hops.hopsworks.exceptions.UserException; import io.hops.hopsworks.jwt.Constants; import io.hops.hopsworks.jwt.JWTController; -import io.hops.hopsworks.jwt.JsonWebToken; import io.hops.hopsworks.jwt.annotation.JWTRequired; import io.hops.hopsworks.jwt.exception.DuplicateSigningKeyException; import io.hops.hopsworks.jwt.exception.InvalidationException; @@ -93,12 +91,6 @@ import javax.ws.rs.core.SecurityContext; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; -import java.time.LocalDateTime; -import java.time.temporal.ChronoUnit; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -230,6 +222,7 @@ public Response serviceLogin(@FormParam("email") String email, @FormParam("passw if (!needLogin(request, null, user)) { return Response.ok().build(); } + if (!userController.isUserInRole(user, "AGENT")) { throw new HopsSecurityException(RESTCodes.SecurityErrorCode.REST_ACCESS_CONTROL, Level.FINE, "Users are not allowed to access this endpoint, use auth/login instead", @@ -237,11 +230,6 @@ public Response serviceLogin(@FormParam("email") String email, @FormParam("passw } request.getSession(); - Collection roles = user.getBbcGroupCollection(); - if (roles == null || roles.isEmpty()) { - throw new UserException(RESTCodes.UserErrorCode.NO_ROLE_FOUND, Level.FINE); - } - statusValidator.checkStatus(user.getStatus()); String saltedPassword = authController.preLoginCheck(user, password, null); @@ -251,47 +239,9 @@ public Response serviceLogin(@FormParam("email") String email, @FormParam("passw authController.registerAuthenticationFailure(user); throw new UserException(RESTCodes.UserErrorCode.AUTHENTICATION_FAILURE, Level.FINE, null, ex.getMessage(), ex); } - - // First generate the one-time tokens for renewal of master token - String renewalKeyName = jwtController.getServiceOneTimeJWTSigningKeyname(user.getUsername(), - request.getRemoteHost()); - LocalDateTime masterExpiration = DateUtils.getNow().plus(settings.getServiceJWTLifetimeMS(), ChronoUnit.MILLIS); - LocalDateTime notBefore = jwtController.computeNotBefore4ServiceRenewalTokens(masterExpiration); - LocalDateTime expiresAt = notBefore.plus(settings.getServiceJWTLifetimeMS(), ChronoUnit.MILLIS); - List userRoles = userUtilities.getUserRoles(user); - - JsonWebToken renewalJWTSpec = new JsonWebToken(); - renewalJWTSpec.setSubject(user.getUsername()); - renewalJWTSpec.setIssuer(settings.getJWTIssuer()); - renewalJWTSpec.setAudience(JWTHelper.SERVICE_RENEW_JWT_AUDIENCE); - renewalJWTSpec.setKeyId(renewalKeyName); - renewalJWTSpec.setNotBefore(DateUtils.localDateTime2Date(notBefore)); - renewalJWTSpec.setExpiresAt(DateUtils.localDateTime2Date(expiresAt)); - - Map claims = new HashMap<>(4); - claims.put(Constants.RENEWABLE, false); - claims.put(Constants.EXPIRY_LEEWAY, 3600); - claims.put(Constants.ROLES, userRoles.toArray(new String[1])); - - String[] oneTimeRenewalTokens = jwtController.generateOneTimeTokens4ServiceJWTRenewal(renewalJWTSpec, claims, - settings.getJWTSigningKeyName()); - - // Then generate the master service token - try { - String signingKeyID = jwtController.getSignKeyID(oneTimeRenewalTokens[0]); - claims.clear(); - // The rest of JWT claims will be added by JWTHelper - claims.put(Constants.RENEWABLE, false); - claims.put(Constants.SERVICE_JWT_RENEWAL_KEY_ID, signingKeyID); - String token = jWTHelper.createToken(user, settings.getJWTIssuer(), claims); - - ServiceJWTDTO renewTokensResponse = new ServiceJWTDTO(); - renewTokensResponse.setRenewTokens(oneTimeRenewalTokens); - return Response.ok().header(AUTHORIZATION, Constants.BEARER + token).entity(renewTokensResponse).build(); - } catch (Exception ex) { - jwtController.deleteSigningKey(renewalKeyName); - throw ex; - } + + String token = jWTHelper.createToken(user, settings.getJWTIssuer(), null); + return Response.ok().header(AUTHORIZATION, Constants.BEARER + token).build(); } @GET diff --git a/hopsworks-api/src/main/java/io/hops/hopsworks/api/user/ServiceJWTDTO.java b/hopsworks-api/src/main/java/io/hops/hopsworks/api/user/ServiceJWTDTO.java deleted file mode 100644 index a81dcc866b..0000000000 --- a/hopsworks-api/src/main/java/io/hops/hopsworks/api/user/ServiceJWTDTO.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of Hopsworks - * Copyright (C) 2019, Logical Clocks AB. All rights reserved - * - * Hopsworks is free software: you can redistribute it and/or modify it under the terms of - * the GNU Affero General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * Hopsworks is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License along with this program. - * If not, see . - */ - -package io.hops.hopsworks.api.user; - -import io.hops.hopsworks.api.jwt.JWTResponseDTO; - -import javax.xml.bind.annotation.XmlRootElement; - -@XmlRootElement -public class ServiceJWTDTO { - - private JWTResponseDTO jwt; - private String[] renewTokens; - - public ServiceJWTDTO() { - } - - public ServiceJWTDTO(JWTResponseDTO jwt, String[] renewTokens) { - this.jwt = jwt; - this.renewTokens = renewTokens; - } - - public JWTResponseDTO getJwt() { - return jwt; - } - - public void setJwt(JWTResponseDTO jwt) { - this.jwt = jwt; - } - - public String[] getRenewTokens() { - return renewTokens; - } - - public void setRenewTokens(String[] renewTokens) { - this.renewTokens = renewTokens; - } -} diff --git a/hopsworks-jwt/src/main/java/io/hops/hopsworks/jwt/Constants.java b/hopsworks-jwt/src/main/java/io/hops/hopsworks/jwt/Constants.java index d543c2da72..ad6ec6921b 100644 --- a/hopsworks-jwt/src/main/java/io/hops/hopsworks/jwt/Constants.java +++ b/hopsworks-jwt/src/main/java/io/hops/hopsworks/jwt/Constants.java @@ -22,8 +22,7 @@ public class Constants { public static final String EXPIRY_LEEWAY = "expLeeway"; public static final String ROLES = "roles"; public static final String WWW_AUTHENTICATE_VALUE="Bearer realm=\"Cauth Realm\""; - public static final String SERVICE_JWT_RENEWAL_KEY_ID = "renewal_key_id"; - + public static final int DEFAULT_EXPIRY_LEEWAY = 60; //60 secs for exp public static final boolean DEFAULT_RENEWABLE = false; diff --git a/hopsworks-jwt/src/main/java/io/hops/hopsworks/jwt/JWTController.java b/hopsworks-jwt/src/main/java/io/hops/hopsworks/jwt/JWTController.java index 09e43d5184..7f6ad405a4 100644 --- a/hopsworks-jwt/src/main/java/io/hops/hopsworks/jwt/JWTController.java +++ b/hopsworks-jwt/src/main/java/io/hops/hopsworks/jwt/JWTController.java @@ -37,9 +37,6 @@ import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import java.security.NoSuchAlgorithmException; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.temporal.ChronoUnit; import java.util.Calendar; import java.util.Collection; import java.util.Date; @@ -55,7 +52,6 @@ import static io.hops.hopsworks.jwt.Constants.DEFAULT_EXPIRY_LEEWAY; import static io.hops.hopsworks.jwt.Constants.DEFAULT_RENEWABLE; import static io.hops.hopsworks.jwt.Constants.EXPIRY_LEEWAY; -import static io.hops.hopsworks.jwt.Constants.ONE_TIME_JWT_SIGNING_KEY_NAME; import static io.hops.hopsworks.jwt.Constants.RENEWABLE; import static io.hops.hopsworks.jwt.Constants.ROLES; @@ -463,70 +459,6 @@ public String renewToken(String token, Date newExp, Date notBefore, boolean inva return renewedToken; } - public String getSignKeyID(String token) { - DecodedJWT jwt = decodeToken(token); - return jwt.getKeyId(); - } - - public String[] generateOneTimeTokens4ServiceJWTRenewal(JsonWebToken jwtSpecs, Map claims, - String defaultJWTSigningKeyName) - throws NoSuchAlgorithmException, SigningKeyNotFoundException { - String[] renewalTokens = new String[5]; - SignatureAlgorithm algorithm = SignatureAlgorithm.valueOf(Constants.ONE_TIME_JWT_SIGNATURE_ALGORITHM); - String[] audienceArray = jwtSpecs.getAudience().toArray(new String[1]); - try { - renewalTokens[0] = createToken(jwtSpecs.getKeyId(), true, jwtSpecs.getIssuer(), - audienceArray, jwtSpecs.getExpiresAt(), jwtSpecs.getNotBefore(), jwtSpecs.getSubject(), claims, - algorithm); - } catch (DuplicateSigningKeyException ex) { - LOGGER.log(Level.FINE, "Signing key already exist for service JWT key " + jwtSpecs.getKeyId() - + ". Removing old one"); - if (defaultJWTSigningKeyName != null) { - if (!defaultJWTSigningKeyName.equals(jwtSpecs.getKeyId()) - && !ONE_TIME_JWT_SIGNING_KEY_NAME.equals(jwtSpecs.getKeyId())) { - deleteSigningKey(jwtSpecs.getKeyId()); - } - } - try { - renewalTokens[0] = createToken(jwtSpecs.getKeyId(), true, jwtSpecs.getIssuer(), - audienceArray, jwtSpecs.getExpiresAt(), jwtSpecs.getNotBefore(), jwtSpecs.getSubject(), claims, - algorithm); - } catch (DuplicateSigningKeyException dskex) { - // This should never happen, we handle it above - } - } - for (int i = 1; i < renewalTokens.length; i++) { - try { - renewalTokens[i] = createToken(jwtSpecs.getKeyId(), false, jwtSpecs.getIssuer(), - audienceArray, jwtSpecs.getExpiresAt(), jwtSpecs.getNotBefore(), jwtSpecs.getSubject(), claims, - algorithm); - } catch (DuplicateSigningKeyException dskex) { - // This should never happen, we do not create new signing key here - } - } - return renewalTokens; - } - - private Date localDateTime2Date(LocalDateTime localDateTime) { - return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); - } - - public LocalDateTime computeNotBefore4ServiceRenewalTokens(LocalDateTime masterExpiration) { - LocalDateTime notBefore = null; - if (masterExpiration.minus(3L, ChronoUnit.MINUTES).isBefore(LocalDateTime.now())) { - notBefore = masterExpiration.minus(3L, ChronoUnit.MILLIS); - } else { - notBefore = masterExpiration.minus(3L, ChronoUnit.MINUTES); - } - return notBefore; - } - - private static final String SERVICE_ONE_TIME_SIGNING_KEYNAME = "%s_%s__%d"; - public String getServiceOneTimeJWTSigningKeyname(String username, String remoteHost) { - long now = System.currentTimeMillis(); - return String.format(SERVICE_ONE_TIME_SIGNING_KEYNAME, username, remoteHost, now); - } - public Map addDefaultClaimsIfMissing(Map userClaims, boolean isRenewable, int leeway, String[] roles) { if (userClaims == null) {