use of com.nimbusds.jwt.SignedJWT in project spring-cloud-gcp by spring-cloud.
the class FirebaseJwtTokenDecoderTests method refreshFlowTests.
@Test
public void refreshFlowTests() throws Exception {
JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256).keyID("one").build();
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().subject("test-subject").expirationTime(Date.from(Instant.now().plusSeconds(60))).build();
SignedJWT signedJWT = signedJwt(keyGeneratorUtils.getPrivateKey(), header, claimsSet);
OAuth2TokenValidator validator = mock(OAuth2TokenValidator.class);
when(validator.validate(any())).thenReturn(OAuth2TokenValidatorResult.success());
RestOperations operations = mockRestOperations();
FirebaseJwtTokenDecoder decoder = new FirebaseJwtTokenDecoder(operations, "https://spring.local", validator);
decoder.decode(signedJWT.serialize());
decoder.decode(signedJWT.serialize());
verify(operations, times(1)).exchange(eq("https://spring.local"), eq(HttpMethod.GET), isNull(), eq(new ParameterizedTypeReference<Map<String, String>>() {
}));
}
use of com.nimbusds.jwt.SignedJWT in project spring-cloud-gcp by spring-cloud.
the class FirebaseJwtTokenDecoderTests method invalidSubject.
@Test
public void invalidSubject() throws Exception {
JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256).keyID("one").build();
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().audience("123456").expirationTime(Date.from(Instant.now().plusSeconds(36000))).issuer("https://securetoken.google.com/123456").issueTime(Date.from(Instant.now().minusSeconds(3600))).claim("auth_time", Instant.now().minusSeconds(3600).getEpochSecond()).build();
SignedJWT signedJWT = signedJwt(keyGeneratorUtils.getPrivateKey(), header, claimsSet);
List<OAuth2TokenValidator<Jwt>> validators = new ArrayList<>();
validators.add(new JwtTimestampValidator());
validators.add(new JwtIssuerValidator("https://securetoken.google.com/123456"));
validators.add(new FirebaseTokenValidator("123456"));
DelegatingOAuth2TokenValidator<Jwt> validator = new DelegatingOAuth2TokenValidator<Jwt>(validators);
RestOperations operations = mockRestOperations();
FirebaseJwtTokenDecoder decoder = new FirebaseJwtTokenDecoder(operations, "https://spring.local", validator);
assertThatExceptionOfType(JwtException.class).isThrownBy(() -> decoder.decode(signedJWT.serialize())).withMessageStartingWith("An error occurred while attempting to decode the Jwt: sub claim can not be empty");
}
use of com.nimbusds.jwt.SignedJWT in project spring-cloud-gcp by spring-cloud.
the class FirebaseJwtTokenDecoderTests method validTokenTests.
@Test
public void validTokenTests() throws Exception {
JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256).keyID("one").build();
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().subject("test-subject").audience("123456").expirationTime(Date.from(Instant.now().plusSeconds(36000))).issuer("https://securetoken.google.com/123456").issueTime(Date.from(Instant.now().minusSeconds(3600))).claim("auth_time", Instant.now().minusSeconds(3600).getEpochSecond()).build();
SignedJWT signedJWT = signedJwt(keyGeneratorUtils.getPrivateKey(), header, claimsSet);
List<OAuth2TokenValidator<Jwt>> validators = new ArrayList<>();
validators.add(new JwtTimestampValidator());
validators.add(new JwtIssuerValidator("https://securetoken.google.com/123456"));
validators.add(new FirebaseTokenValidator("123456"));
DelegatingOAuth2TokenValidator<Jwt> validator = new DelegatingOAuth2TokenValidator<Jwt>(validators);
RestOperations operations = mockRestOperations();
FirebaseJwtTokenDecoder decoder = new FirebaseJwtTokenDecoder(operations, "https://spring.local", validator);
Jwt jwt = decoder.decode(signedJWT.serialize());
assertThat(jwt.getClaims()).isNotEmpty();
}
use of com.nimbusds.jwt.SignedJWT in project ranger by apache.
the class RangerSSOAuthenticationFilter method doFilter.
/*
* doFilter of RangerSSOAuthenticationFilter is the first in the filter list so in this it check for the request
* if the request is from browser, doesn't contain local login and sso is enabled then it process the request against knox sso
* else if it's ssoenable and the request is with local login string then it show's the appropriate msg
* else if ssoenable is false then it contiunes with further filters as it was before sso
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
String xForwardedURL = RestUtil.constructForwardableURL(httpRequest);
if (httpRequest.getRequestedSessionId() != null && !httpRequest.isRequestedSessionIdValid()) {
synchronized (httpRequest.getServletContext()) {
if (httpRequest.getServletContext().getAttribute(httpRequest.getRequestedSessionId()) != null && "locallogin".equals(httpRequest.getServletContext().getAttribute(httpRequest.getRequestedSessionId()).toString())) {
httpRequest.getSession().setAttribute("locallogin", "true");
httpRequest.getServletContext().removeAttribute(httpRequest.getRequestedSessionId());
}
}
}
RangerSecurityContext context = RangerContextHolder.getSecurityContext();
UserSessionBase session = context != null ? context.getUserSession() : null;
boolean ssoEnabled = session != null ? session.isSSOEnabled() : PropertiesUtil.getBooleanProperty("ranger.sso.enabled", false);
String userAgent = httpRequest.getHeader("User-Agent");
if (httpRequest.getSession() != null) {
if (httpRequest.getSession().getAttribute("locallogin") != null) {
servletRequest.setAttribute("ssoEnabled", false);
filterChain.doFilter(servletRequest, servletResponse);
return;
}
}
// If sso is enable and request is not for local login and is from browser then it will go inside and try for knox sso authentication
if (ssoEnabled && !httpRequest.getRequestURI().contains(RestUtil.LOCAL_LOGIN_URL)) {
// Note : Need to remove !isAuthenticated() after knoxsso solve the bug from cross-origin script
if (jwtProperties != null && !isAuthenticated()) {
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
String serializedJWT = getJWTFromCookie(httpRequest);
// if we get the hadoop-jwt token from the cookies then will process it further
if (serializedJWT != null) {
SignedJWT jwtToken = null;
try {
jwtToken = SignedJWT.parse(serializedJWT);
boolean valid = validateToken(jwtToken);
// if the public key provide is correct and also token is not expired the process token
if (valid) {
String userName = jwtToken.getJWTClaimsSet().getSubject();
LOG.info("SSO login user : " + userName);
String rangerLdapDefaultRole = PropertiesUtil.getProperty("ranger.ldap.default.role", "ROLE_USER");
// if we get the userName from the token then log into ranger using the same user
if (userName != null && !userName.trim().isEmpty()) {
final List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority(rangerLdapDefaultRole));
final UserDetails principal = new User(userName, "", grantedAuths);
final Authentication finalAuthentication = new UsernamePasswordAuthenticationToken(principal, "", grantedAuths);
WebAuthenticationDetails webDetails = new WebAuthenticationDetails(httpRequest);
((AbstractAuthenticationToken) finalAuthentication).setDetails(webDetails);
RangerAuthenticationProvider authenticationProvider = new RangerAuthenticationProvider();
authenticationProvider.setSsoEnabled(ssoEnabled);
Authentication authentication = authenticationProvider.authenticate(finalAuthentication);
authentication = getGrantedAuthority(authentication);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(servletRequest, httpServletResponse);
} else // if the token is not valid then redirect to knox sso
{
if (isWebUserAgent(userAgent)) {
String ssourl = null;
String ajaxRequestHeader = httpRequest.getHeader("X-Requested-With");
if ("XMLHttpRequest".equals(ajaxRequestHeader)) {
ssourl = constructLoginURLForApi(httpRequest, xForwardedURL);
if (LOG.isDebugEnabled()) {
LOG.debug("ajaxRequestHeader redirectUrl = " + ssourl);
}
httpServletResponse.setHeader("X-Frame-Options", "DENY");
httpServletResponse.setStatus(RangerConstants.SC_AUTHENTICATION_TIMEOUT);
httpServletResponse.setHeader("X-Rngr-Redirect-Url", ssourl);
} else {
ssourl = RestUtil.constructRedirectURL(httpRequest, authenticationProviderUrl, xForwardedURL, originalUrlQueryParam);
if (LOG.isDebugEnabled()) {
LOG.debug("SSO URL = " + ssourl);
}
httpServletResponse.sendRedirect(ssourl);
}
} else {
filterChain.doFilter(servletRequest, httpServletResponse);
}
}
} catch (ParseException e) {
LOG.warn("Unable to parse the JWT token", e);
}
} else // if the jwt token is not available then redirect it to knox sso
{
if (isWebUserAgent(userAgent)) {
String ssourl = null;
String ajaxRequestHeader = httpRequest.getHeader("X-Requested-With");
if ("XMLHttpRequest".equals(ajaxRequestHeader)) {
ssourl = constructLoginURLForApi(httpRequest, xForwardedURL);
if (LOG.isDebugEnabled()) {
LOG.debug("ajaxRequestHeader redirectUrl = " + ssourl);
}
httpServletResponse.setHeader("X-Frame-Options", "DENY");
httpServletResponse.setStatus(RangerConstants.SC_AUTHENTICATION_TIMEOUT);
httpServletResponse.setHeader("X-Rngr-Redirect-Url", ssourl);
} else {
ssourl = RestUtil.constructRedirectURL(httpRequest, authenticationProviderUrl, xForwardedURL, originalUrlQueryParam);
if (LOG.isDebugEnabled()) {
LOG.debug("SSO URL = " + ssourl);
}
httpServletResponse.sendRedirect(ssourl);
}
} else {
filterChain.doFilter(servletRequest, httpServletResponse);
}
}
} else // if property is not loaded or is already authenticated then proceed further with next filter
{
filterChain.doFilter(servletRequest, servletResponse);
}
} else if (ssoEnabled && ((HttpServletRequest) servletRequest).getRequestURI().contains(RestUtil.LOCAL_LOGIN_URL) && isWebUserAgent(userAgent) && isAuthenticated()) {
// If already there's an active session with sso and user want's to switch to local login(i.e without sso) then it won't be navigated to local login
// In this scenario the user as to use separate browser
String url = ((HttpServletRequest) servletRequest).getRequestURI().replace(RestUtil.LOCAL_LOGIN_URL + "/", "");
url = url.replace(RestUtil.LOCAL_LOGIN_URL, "");
LOG.warn("There is an active session and if you want local login to ranger, try this on a separate browser");
((HttpServletResponse) servletResponse).sendRedirect(url);
} else // if sso is not enable or the request is not from browser then proceed further with next filter
{
filterChain.doFilter(servletRequest, servletResponse);
}
}
use of com.nimbusds.jwt.SignedJWT in project SEPA by arces-wot.
the class SecurityManager method getToken.
/**
* It requests a token to the Authorization Server. A token request should be
* made when the current token is expired or it is the first token. If the token
* is not expired, the "invalid_grant" error is returned.
*
* @param encodedCredentials the client credentials encoded using Base64
* @return JWTResponse in case of success, ErrorResponse otherwise
* @throws SEPASecurityException
* @see JWTResponse
* @see ErrorResponse
*
* <pre>
* POST https://wot.arces.unibo.it:8443/oauth/token
*
* Content-Type: application/x-www-form-urlencoded
* Accept: application/json
* Authorization: Basic Basic64(id:secret)
*
* Response example:
* {
* "access_token": "eyJraWQiOiIyN.........",
* "token_type": "bearer",
* "expires_in": 3600
* }
*
* Error response example:
* {
* "error":"Unless specified otherwise see RFC6749. Otherwise, this is specific of the SPARQL 1.1 SE Protocol",
* "error_description":"Unless specified otherwise, see RFC6749. Otherwise, this is specific to the SPARQL 1.1 SE Protocol", (OPTIONAL)
* "status_code" : the HTTP status code (should be 400 for all Oauth 2.0 errors).
* }
*
* According to RFC6749, the error member can assume the following values: invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_grant_type, invalid_scope.
*
* invalid_request
* The request is missing a required parameter, includes an
* unsupported parameter value (other than grant type),
* repeats a parameter, includes multiple credentials,
* utilizes more than one mechanism for authenticating the
* client, or is otherwise malformed.
*
* invalid_client
* Client authentication failed (e.g., unknown client, no
* client authentication included, or unsupported
* authentication method). The authorization server MAY
* return an HTTP 401 (Unauthorized) status code to indicate
* which HTTP authentication schemes are supported. If the
* client attempted to authenticate via the "Authorization"
* request header field, the authorization server MUST
* respond with an HTTP 401 (Unauthorized) status code and
* include the "WWW-Authenticate" response header field
* matching the authentication scheme used by the client.
*
* invalid_grant
* The provided authorization grant (e.g., authorization
* code, resource owner credentials) or refresh token is
* invalid, expired, revoked, does not match the redirection
* URI used in the authorization request, or was issued to
* another client.
*
* unauthorized_client
* The authenticated client is not authorized to use this
* authorization grant type.
*
* unsupported_grant_type
* The authorization grant type is not supported by the
* authorization server.
* </pre>
*/
public synchronized Response getToken(String encodedCredentials) {
logger.debug("GET TOKEN");
// Decode credentials
byte[] decoded = null;
try {
decoded = Base64.getDecoder().decode(encodedCredentials);
} catch (IllegalArgumentException e) {
logger.error("Not authorized");
return new ErrorResponse(HttpStatus.SC_UNAUTHORIZED, "invalid_request", e.getMessage());
}
// Parse credentials
String decodedCredentials = new String(decoded);
// BUG SOLVED. The clientID may contain ":"
// e.g., urn:epc:id:gid:0.1.410D23751450344850323220
int marker = decodedCredentials.lastIndexOf(":");
if (marker == -1) {
logger.error("Wrong Basic authorization");
return new ErrorResponse(HttpStatus.SC_UNAUTHORIZED, "invalid_client", "Delimiter ':' is missing. Wrong credentials format: " + decodedCredentials);
}
// String[] clientID = decodedCredentials.split(":");
// if (clientID == null) {
// logger.error("Wrong Basic authorization");
// return new ErrorResponse(HttpStatus.SC_UNAUTHORIZED, "invalid_client",
// "Client id not found: " + decodedCredentials);
// }
// if (clientID.length != 2) {
// logger.error("Wrong Basic authorization");
// return new ErrorResponse(HttpStatus.SC_UNAUTHORIZED, "invalid_client",
// "Wrong credentials: " + decodedCredentials);
// }
// String id = decodedCredentials.split(":")[0];
// String secret = decodedCredentials.split(":")[1];
String id = decodedCredentials.substring(0, marker);
String secret = decodedCredentials.substring(marker + 1);
logger.debug("Credentials: " + id + " " + secret);
// Verify credentials
try {
if (!containsCredentials(id)) {
logger.error("Client id: " + id + " is not registered");
return new ErrorResponse(HttpStatus.SC_BAD_REQUEST, "unauthorized_client", "Client identity " + id + " not found");
}
} catch (SEPASecurityException e2) {
return new ErrorResponse(HttpStatus.SC_BAD_REQUEST, "unauthorized_client", e2.getMessage());
}
try {
if (!checkCredentials(id, secret)) {
logger.error("Wrong secret: " + secret + " for client id: " + id);
return new ErrorResponse(HttpStatus.SC_BAD_REQUEST, "unauthorized_client", "Wrong credentials for identity " + id);
}
} catch (SEPASecurityException e2) {
return new ErrorResponse(HttpStatus.SC_BAD_REQUEST, "unauthorized_client", e2.getMessage());
}
// Prepare JWT with claims set
JWTClaimsSet.Builder claimsSetBuilder = new JWTClaimsSet.Builder();
Date now = new Date();
// Check if the token is not expired
try {
if (containsJwt(id)) {
Date expiring = getTokenExpiringDate(id);
long expiringUnixSeconds = (expiring.getTime() / 1000) * 1000;
long nowUnixSeconds = (now.getTime() / 1000) * 1000;
long delta = expiringUnixSeconds - nowUnixSeconds;
// Expires if major than current time
logger.debug("ID: " + id + " ==> Token will expire in: " + delta + " ms");
if (delta > 0) {
logger.warn("Token is NOT EXPIRED. Return the current token.");
JWTResponse jwt = null;
try {
jwt = new JWTResponse(getJwt(id));
} catch (SEPASecurityException e) {
logger.error(e.getMessage());
return new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "security_error", "Failed to retrieve expiring period");
}
return jwt;
}
logger.debug("Token is EXPIRED. Release a fresh token.");
}
} catch (SEPASecurityException e2) {
return new ErrorResponse(HttpStatus.SC_BAD_REQUEST, "security_error", e2.getMessage());
}
/*
* 4.1.1. "iss" (Issuer) Claim
*
* The "iss" (issuer) claim identifies the principal that issued the JWT. The
* processing of this claim is generally application specific. The "iss" value
* is a case-sensitive string containing a StringOrURI value. Use of this claim
* is OPTIONAL.
*/
// try {
// claimsSetBuilder.issuer(auth.getIssuer());
// } catch (SEPASecurityException e1) {
// return new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "invalid_issuer",
// e1.getMessage());
// }
/*
* 4.1.2. "sub" (Subject) Claim
*
* The "sub" (subject) claim identifies the principal that is the subject of the
* JWT. The Claims in a JWT are normally statements about the subject. The
* subject value MUST either be scoped to be locally unique in the context of
* the issuer or be globally unique. The processing of this claim is generally
* application specific. The "sub" value is a case-sensitive string containing a
* StringOrURI value. Use of this claim is OPTIONAL.
*/
claimsSetBuilder.subject(id);
/*
* 4.1.3. "aud" (Audience) Claim
*
* The "aud" (audience) claim identifies the recipients that the JWT is intended
* for. Each principal intended to process the JWT MUST identify itself with a
* value in the audience claim. If the principal processing the claim does not
* identify itself with a value in the "aud" claim when this claim is present,
* then the JWT MUST be rejected. In the general case, the "aud" value is an
* array of case- sensitive strings, each containing a StringOrURI value. In the
* special case when the JWT has one audience, the "aud" value MAY be a single
* case-sensitive string containing a StringOrURI value. The interpretation of
* audience values is generally application specific. Use of this claim is
* OPTIONAL.
*/
// ArrayList<String> audience = new ArrayList<String>();
// try {
// audience.add(auth.getHttpsAudience());
// } catch (SEPASecurityException e1) {
// return new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "invalid_https_audience",
// e1.getMessage());
// }
// try {
// audience.add(auth.getWssAudience());
// } catch (SEPASecurityException e1) {
// return new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "invalid_wss_audience",
// e1.getMessage());
// }
// claimsSetBuilder.audience(audience);
/*
* 4.1.4. "exp" (Expiration Time) Claim
*
* The "exp" (expiration time) claim identifies the expiration time on or after
* which the JWT MUST NOT be accepted for processing. The processing of the
* "exp" claim requires that the current date/time MUST be before the expiration
* date/time listed in the "exp" claim. Implementers MAY provide for some small
* leeway, usually no more than a few minutes, to account for clock skew. Its
* value MUST be a number containing a NumericDate value. Use of this claim is
* OPTIONAL.
*/
/*
* NOTICE: this date is serialized as SECONDS from UNIX time NOT milliseconds!
*/
// Define the expiration time
Date expires;
try {
expires = new Date(now.getTime() + (getTokenExpiringPeriod(id) * 1000));
} catch (SEPASecurityException e1) {
logger.error(e1.getMessage());
return new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "security_error", "Failed to retrieve expiring period");
}
claimsSetBuilder.expirationTime(expires);
/*
* 4.1.5. "nbf" (Not Before) Claim
*
* The "nbf" (not before) claim identifies the time before which the JWT MUST
* NOT be accepted for processing. The processing of the "nbf" claim requires
* that the current date/time MUST be after or equal to the not-before date/time
* listed in the "nbf" claim. Implementers MAY provide for some small leeway,
* usually no more than a few minutes, to account for clock skew. Its value MUST
* be a number containing a NumericDate value. Use of this claim is OPTIONAL.
*/
// claimsSetBuilder.notBeforeTime(before);
/*
* 4.1.6. "iat" (Issued At) Claim
*
* The "iat" (issued at) claim identifies the time at which the JWT was issued.
* This claim can be used to determine the age of the JWT. Its value MUST be a
* number containing a NumericDate value. Use of this claim is OPTIONAL.
*/
claimsSetBuilder.issueTime(now);
/*
* 4.1.7. "jti" (JWT ID) Claim
*
* The "jti" (JWT ID) claim provides a unique identifier for the JWT. The
* identifier value MUST be assigned in a manner that ensures that there is a
* negligible probability that the same value will be accidentally assigned to a
* different data object; if the application uses multiple issuers, collisions
* MUST be prevented among values produced by different issuers as well. The
* "jti" claim can be used to prevent the JWT from being replayed. The "jti"
* value is a case- sensitive string. Use of this claim is OPTIONAL.
*/
// claimsSetBuilder.jwtID(id);
JWTClaimsSet jwtClaims = claimsSetBuilder.build();
// ******************************
// Sign JWT with private RSA key
// ******************************
SignedJWT signedJWT;
try {
signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.RS256), JWTClaimsSet.parse(jwtClaims.toString()));
} catch (ParseException e) {
logger.error(e.getMessage());
return new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "parsing_exception", "ParseException: " + e.getMessage());
}
try {
signedJWT.sign(signer);
} catch (JOSEException e) {
logger.error(e.getMessage());
return new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "sign_exception", "JOSEException: " + e.getMessage());
}
// Add the token to the released tokens
try {
addJwt(id, signedJWT);
} catch (SEPASecurityException e1) {
logger.error(e1.getMessage());
return new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "security_error", e1.getMessage());
}
JWTResponse jwt = null;
try {
jwt = new JWTResponse(signedJWT);
} catch (SEPASecurityException e) {
logger.error(e.getMessage());
return new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "security_error", "Failed to retrieve expiring period");
}
logger.debug("Released token: " + jwt);
return jwt;
}
Aggregations