Rest API java, JSON Web token authentication : invalid signature - rest

In Java, I try to set up a JWT authentication on a Rest API using jersey 1.9.
I'm using a friend's code sample (his token are valid with that code) and io.jsonwebtoken to generate token but I keep getting an Invalid signature warning when I test them on https://jwt.io/.
I've done some research and tried to fix that but I'm running out of ideas.
Example of invalid token I get with that code:
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIyIiwiaWF0IjoxNDg1MDI2MDgzLCJzdWIiOiJodHRwOi8vbG9jYWxob3N0OjkxODAvVHJvY1RvblNhdm9pci8iLCJpc3MiOiJzZXJnZW50LWNoZWYiLCJleHAiOjE1MTY1NjIwODN9.HY8S7QbOhSB22d1_Dkmtg6qCiKxQRKz9W1etMqDookw
This is the login path and the method I use to create those token :
import java.security.Key;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.xml.bind.DatatypeConverter;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.TextCodec;
import io.jsonwebtoken.impl.crypto.MacProvider;
import dao.UserDao;
import model.User;
#Path("/home")
public class MainController {
UserController userCtrl = new UserController();
//The not really secret key
String key = "supersecretkey";
#POST
#Path("login")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response Login(
#FormParam("username") String username,
#FormParam("password") String password){
if (username == null || password == null) {
return Response
.status(Status.PRECONDITION_FAILED)
.build();
}
User user = userCtrl.Authenticate(username,password);
if (user == null) {
return Response
.status(Status.FORBIDDEN)
.build();
}
String token = createJWT(user.getUserID()+"",user.getUserName(),"http://localhost:8080/rest_api/",TimeUnit.DAYS.toMillis(365));
return Response
.status(Status.OK)
.entity(token)
.build();
}
private String createJWT(String id, String issuer, String subject, long ttlMillis) {
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//We will sign our JWT with our ApiKey secret
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(key);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//Let's set the JWT Claims
JwtBuilder builder = Jwts.builder().setId(id)
.setIssuedAt(now)
.setSubject(subject)
.setIssuer(issuer)
.signWith(signatureAlgorithm, signingKey );
//if it has been specified, let's add the expiration
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
//Builds the JWT and serializes it to a compact, URL-safe string
return builder.compact();
}
}
Solved
I don't really know what was wrong with my secret key but I manage to validate my token by changing my key generation:
private static final Key secret = MacProvider.generateKey(SignatureAlgorithm.HS256);
private static final byte[] secretBytes = secret.getEncoded();
public static final String base64SecretBytes = Base64.getEncoder().encodeToString(secretBytes);

Related

Micronaut HTTP Client Fails to Bind Response that is Missing Content-Type Header

I've successfully used the Micronaut HTTP Client with several different external services in the past. However, I'm really struggling with one external service. I think it might be related to the fact that the response from the external service does not contain a Content-Type header, but I'm not sure.
The client and response type are defined in the same groovy file.
package us.cloudcard.api.transact
import groovy.transform.ToString
import io.micronaut.http.HttpResponse
import io.micronaut.http.MediaType
import io.micronaut.http.annotation.Body
import io.micronaut.http.annotation.Post
import io.micronaut.http.annotation.Produces
import io.micronaut.http.client.annotation.Client
import javax.validation.constraints.NotNull
#Client('${transact.url}')
interface TransactAuthenticationClient {
#Post
#Produces(MediaType.TEXT_PLAIN)
HttpResponse<TransactAuthenticationResponse> authenticate(#NotNull #Body String token)
}
#ToString
class TransactAuthenticationResponse {
Boolean Expired
String InstitutionId
String UserName
String customCssUrl
String email
String role
}
I'm testing it with a simple controller that just calls the client and renders the response status and body.
package us.cloudcard.api
import grails.compiler.GrailsCompileStatic
import grails.converters.JSON
import grails.plugin.springsecurity.annotation.Secured
import io.micronaut.http.HttpResponse
import org.springframework.beans.factory.annotation.Autowired
import us.cloudcard.api.transact.TransactAuthenticationClient
import us.cloudcard.api.transact.TransactAuthenticationResponse
#GrailsCompileStatic
#Secured("permitAll")
class MyController {
static responseFormats = ['json', 'xml']
#Autowired
TransactAuthenticationClient transactAuthenticationClient
def show(String id) {
String goodToken = "5753D...REDACTED...647F"
HttpResponse response = transactAuthenticationClient.authenticate(goodToken)
TransactAuthenticationResponse authenticationResponse = response.body()
log.error("status: ${response.status()} body: $authenticationResponse")
render "status: ${response.status()} body: $authenticationResponse"
}
}
However, the result I get is
status: OK body: null
Making the same request in Postman results in the correct response
When I debug, I can inspect the HttpResponse object and see all the correct headers, so I know I'm making the request successfully. I just can't bind the response.
I tried changing the client to bind to a String
#Post
#Produces(MediaType.TEXT_PLAIN)
HttpResponse<String> authenticate(#NotNull #Body String token)
and I got the following response
status: OK body: PooledSlicedByteBuf(ridx: 0, widx: 176, cap: 176/176, unwrapped: PooledUnsafeDirectByteBuf(ridx: 484, widx: 484, cap: 513))
This was interesting because the widx: 176, cap: 176/176 perfectly matched the content length of the successful response.
I am really at a loss, so I would appreciate any help you can give.
Thanks in advance for your help!
TL;DR: The Micronaut HTTP Client is not designed to work for this API
The Micronaut HTTP Client cannot consume APIs that do not include a content-type header in the response. I talked with Jeff Scott Brown about this, and that's just how Micronaut is designed. If there's no content-type header in the response, the client won't know how to parse the response body.
Work-Around
package us.cloudcard.api.transact
import groovy.json.JsonSlurper
import groovy.transform.ToString
import org.apache.http.client.methods.CloseableHttpResponse
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.HttpClientBuilder
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
#Component
class TransactAuthenticationClient {
#Value('${transact.url}')
String transactAuthenticationUrl
TransactAuthenticationResponse workaround2(String token) {
HttpPost post = new HttpPost(transactAuthenticationUrl)
post.addHeader("content-type", "text/plain")
post.setEntity(new StringEntity(token))
CloseableHttpClient client = HttpClientBuilder.create().build()
CloseableHttpResponse response = client.execute(post)
def bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))
def json = bufferedReader.getText()
println "response: \n" + json
def resultMap = new JsonSlurper().parseText(json)
return new TransactAuthenticationResponse(resultMap)
}
}
#ToString(includeNames = true)
class TransactAuthenticationResponse {
Boolean Expired
String InstitutionId
String UserName
String customCssUrl
String email
String role
}
JUST FYI: Before I found the above workaround, I tried this and it also does not work.
TransactAuthenticationResponse thisAlsoDoesNotWork (String token) {
String baseUrl = "https://example.com"
HttpClient client = HttpClient.create(baseUrl.toURL())
HttpRequest request = HttpRequest.POST("/path/to/endpoint", token)
HttpResponse<String> resp = client.toBlocking().exchange(request, String)
String json = resp.body()
println "json: $json"
ObjectMapper objectMapper = new ObjectMapper()
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
TransactAuthenticationResponse response = objectMapper.readValue(json, TransactAuthenticationResponse)
return response
}
Having the same problem, this is the best solution I found so far:
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.convert.TypeConverter;
import io.netty.buffer.ByteBuf;
// (...)
ConversionService.SHARED.addConverter(ByteBuf.class, String.class, new TypeConverter<ByteBuf, String>() {
#Override
public Optional<String> convert(ByteBuf object, Class<String> targetType, ConversionContext context) {
return Optional.ofNullable(object).map(bb -> bb.toString(StandardCharsets.UTF_8));
}
});
HttpRequest<String> req = HttpRequest.POST("<url>", "<body>");
// res is instance of io.micronaut.http.client.netty.FullNettyClientHttpResponse which uses the shared conversion service as "last chance" to convert the response body
HttpResponse<String> res = httpClient.toBlocking().exchange(req);
String responseBody = res.getBody(String.class).get();

How to use JWT using JJWT with Play Framework Java?

I am trying to use Zoom API which requires using JWT. I have successfully using node.js to generate JWT and call the Zoom API like this:
var jwt = require('jsonwebtoken');
var zoom_key = "abcd";
var zoom_secret = "efgh";
var payload = {
iss: Zoom_Key,
exp: ((new Date()).getTime() + 3600)
};
//Automatically creates header, and returns JWT
var token = jwt.sign(payload, zoom_secret);
module.exports = token;
However, right now I am trying to use the same way in JAVA. When I using the token by JJWT, it always give the the "invalid token" error message from zoom api. Can any one help me figure out the reason?
First, I create a Playload class in Playload.java like this:
// in Playload.java
package palyload;
public class Playload {
public String iss;
public Playload(String iss) {
this.iss = iss;
}
}
Second,
I import JJWT and play.libs.Json to generate JWT token like this:
package controllers;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
import palyload.Playload;
public class JWT extends Controller {
private static final String zoom_key = "abcd";
private static final String zoom_secret = "efgh";
private static final String baseUrl = "https://api.zoom.us/v2/users/?access_token=";
public String setToken (Object obj) {
String token = "";
Map<String, Object> map = new HashMap<>();
map.put("json", Json.toJson(obj));
try {
token = Jwts.builder()
.setClaims(map)
.setExpiration(Date.from(ZonedDateTime.now(ZoneId.systemDefault()).plusSeconds(3600).toInstant()))
.signWith(SignatureAlgorithm.HS256, zoom_secret)
.compact();
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
System.out.println(Jwts.parser().setSigningKey(zoom_secret).parseClaimsJws(token).getBody().getSubject().toString());
// System.out.println(map.toString());
return token;
}
public String getToken () {
Playload pl = new Playload(zoom_key);
System.out.println("playload: " + Json.toJson(pl).toString());
return setToken(pl);
}
public String setUrl () {
return baseUrl + getToken();
}
public Result getUrl () {
return ok(setUrl());
}
}
Have no idea why this token url is not correct like Node.js one?

WSO2 Self contained AccessToken claims configuration -- the "sub" field

I am working on WSO2IS, and had been able to get a self contained access token out of WSO2IS by Oauth2 "password" grant type by following this post
I am also able to verify the signature of the token in application (see this post)
yet there is still one final step that I can not pass
here is a sample of access token I have got out of WSO2IS
{iss=https://localhost:9443/oauth2/token, sub=wjz#carbon.super, aud=[J3lbMMMJFwXB6neKzXv030S9lfga], exp=1488710173, iat=1488706573, azp=J3lbMMMJFwXB6neKzXv030S9lfga}
you can see that value of "sub" is a username, which correspond to the claim " http://wso2.org/claims/username".
I want to change the configure in WSO2IS so that the "sub" correspond to claim " http://wso2.org/claims/userid"
I changed the "Claim Configuration" under "Service Providers";
I also changed the "sub" in the "http://wso2.org/oidc/claim" under "Claims". but can not get any success.
are there anything I have missed?
please advise
thanks
I finally have this problem solved by coding instead of configuring.
I had implemented an extension for a Self-Contained Access Token (JWT in Oauth2) Generator by followed this post . I build the jar, and upload the jar under /repository/components/lib/
I just checkout this repo , and made the following changes
/**
* For a locally authenticated user, subject identifier is supposed to be as below.
* <userstore_domain>/<username>#<tenant_domain>.
*
* yet somehow, what I got is <username>#<tenant_domain>
* #param SubjectId
* #return
* #throws IdentityOAuth2Exception
*/
private static SubjectTriple parseSubjectId(String subjectId) throws IdentityOAuth2Exception{
if (StringUtils.isBlank(subjectId)){
throw new IdentityOAuth2Exception("invalid subject identifier");
}
/*
* domain may not present
*/
String sid = null;
SubjectTriple st = new SubjectTriple();
if(StringUtils.contains(subjectId, '/')){
st.domain = StringUtils.substringBeforeLast(subjectId, "/");
sid = StringUtils.substringAfterLast(subjectId, "/");
}else{
sid = subjectId;
}
st.username = StringUtils.substringBeforeLast(sid, "#");
st.profile = StringUtils.substringAfterLast(sid, "#");
return st;
}
/**
* To build id token from OauthToken request message context
*
* #param request Token request message context
* #return Signed jwt string.
* #throws IdentityOAuth2Exception
*/
protected String buildIDToken(OAuthTokenReqMessageContext request)
throws IdentityOAuth2Exception {
String issuer = OAuth2Util.getIDTokenIssuer();
long lifetimeInMillis = OAuthServerConfiguration.getInstance().
getApplicationAccessTokenValidityPeriodInSeconds() * 1000;
long curTimeInMillis = Calendar.getInstance().getTimeInMillis();
SubjectTriple triple = parseSubjectId(request.getAuthorizedUser().getAuthenticatedSubjectIdentifier());
String userId = null;
try {
userId = CarbonContext.getThreadLocalCarbonContext().getUserRealm().getUserStoreManager()
.getUserClaimValue(triple.username, Constants.LOCAL_CLAIM__UserID, triple.profile);
} catch (UserStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String clientId = request.getOauth2AccessTokenReqDTO().getClientId();
// Set claims to jwt token.
JWTClaimsSet jwtClaimsSet = new JWTClaimsSet();
jwtClaimsSet.setIssuer(issuer);
jwtClaimsSet.setSubject(userId);
jwtClaimsSet.setAudience(Arrays.asList(clientId));
jwtClaimsSet.setClaim(Constants.AUTHORIZATION_PARTY, clientId);
jwtClaimsSet.setExpirationTime(new Date(curTimeInMillis + lifetimeInMillis));
jwtClaimsSet.setIssueTime(new Date(curTimeInMillis));
if (JWSAlgorithm.NONE.getName().equals(signatureAlgorithm.getName())) {
return new PlainJWT(jwtClaimsSet).serialize();
}
return signJWT(jwtClaimsSet, request);
}
/**
* Build a signed jwt token from authorization request message context
*
* #param request Oauth authorization message context
* #return Signed jwt string
* #throws IdentityOAuth2Exception
*/
protected String buildIDToken(OAuthAuthzReqMessageContext request)
throws IdentityOAuth2Exception {
String issuer = OAuth2Util.getIDTokenIssuer();
long lifetimeInMillis = OAuthServerConfiguration.getInstance().
getApplicationAccessTokenValidityPeriodInSeconds() * 1000;
long curTimeInMillis = Calendar.getInstance().getTimeInMillis();
OAuth2AuthorizeReqDTO dto = request.getAuthorizationReqDTO();
SubjectTriple triple = parseSubjectId(dto.getUser().getAuthenticatedSubjectIdentifier());
String userId = null;
try {
userId = CarbonContext.getThreadLocalCarbonContext().getUserRealm().getUserStoreManager()
.getUserClaimValue(triple.username, Constants.LOCAL_CLAIM__UserID, triple.profile);
} catch (UserStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String consumerKey = dto.getConsumerKey();
JWTClaimsSet jwtClaimsSet = new JWTClaimsSet();
jwtClaimsSet.setIssuer(issuer);
jwtClaimsSet.setSubject(userId);
jwtClaimsSet.setAudience(Arrays.asList(consumerKey));
jwtClaimsSet.setClaim(Constants.AUTHORIZATION_PARTY,consumerKey);
jwtClaimsSet.setExpirationTime(new Date(curTimeInMillis + lifetimeInMillis));
jwtClaimsSet.setIssueTime(new Date(curTimeInMillis));
if (JWSAlgorithm.NONE.getName().equals(signatureAlgorithm.getName())) {
return new PlainJWT(jwtClaimsSet).serialize();
}
return signJWT(jwtClaimsSet, request);
}
the imports
import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.jwt.SignedJWT;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.core.util.KeyStoreManager;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext;
import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO;
import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
import org.wso2.carbon.identity.oauth2.token.OauthTokenIssuerImpl;
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
import org.wso2.carbon.user.api.UserStoreException;
import java.security.Key;
import java.security.interfaces.RSAPrivateKey;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

Adding a signature to a certificate

I have some odd requirements that I have to live with. I need to pass my crypto system a TBS certificate, they will sign it and send back a String of the signature which I need to incorporate into a certificate to make a signed certificate.
Looking at com.ibm.security.x509.X509CertImpl and various BouncyCastle posts on SO, I can't find out how to do that.
Questions:
Is this possible ?
If so, how ?
I'd refer to the source code for the BouncyCastle X509v3CertificateBuilder class (pkix jar), and tweak it to suit your needs. Note that this class uses a V3TBSCertificateGenerator to produce the TBSCertificate. That's an ASN.1 object that you can DER encode. Then you can get the DER encoding signed by the "crypto system". Then consult X509v3CertificateBuilder.build() method as to how to put the TBS certificate and signature together into the final X.509 certificate.
I've put together an example that shows one way to do it. Most of this code was stolen from the bouncycastle pkix or lwcrypto libraries, but any bugs are almost certainly mine. The most important method to concentrate on below is generateCert. The rest of the code is test harness to drive the test.
The code is specifically written to need only the bounycastle bcpkix and lwcrypto jars. It could be shortened somewhat if the bcprov jar was used instead of lwcrypto.
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.bc.BcX509v3CertificateBuilder;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
import javax.security.auth.x500.X500Principal;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
public class Main {
private static class TBSCertPlusSignature {
private final byte[] encodedTbsCert;
private final byte[] signature;
public TBSCertPlusSignature(byte[] encodedTbsCert, byte[] signature) {
this.encodedTbsCert = encodedTbsCert;
this.signature = signature;
}
public byte[] getEncodedTbsCert() {
return encodedTbsCert;
}
public byte[] getSignature() {
return signature;
}
}
private static TBSCertPlusSignature makeTestCert(KeyPair keyPair) throws Exception {
Date now = new Date();
Date nowPlus1Hour = new Date(now.getTime() + 1000 * 60 * 60 * 1L);
byte[] encodedName = new X500Principal("CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").getEncoded();
X500Name issuer = X500Name.getInstance(encodedName);
X500Name subject = issuer;
RSAPublicKey rsaPub = (RSAPublicKey) keyPair.getPublic();
RSAKeyParameters rsaPubParams = new RSAKeyParameters(false, rsaPub.getModulus(), rsaPub.getPublicExponent());
BcX509v3CertificateBuilder certBuilder = new BcX509v3CertificateBuilder(
issuer,
BigInteger.valueOf(100L),
now,
nowPlus1Hour,
subject,
rsaPubParams
);
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSA");
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
RSAPrivateCrtKey rsaPriv = (RSAPrivateCrtKey) keyPair.getPrivate();
RSAPrivateCrtKeyParameters rsaPrivParams = new RSAPrivateCrtKeyParameters(
rsaPriv.getModulus(),
rsaPriv.getPublicExponent(),
rsaPriv.getPrivateExponent(),
rsaPriv.getPrimeP(),
rsaPriv.getPrimeQ(),
rsaPriv.getPrimeExponentP(),
rsaPriv.getPrimeExponentQ(),
rsaPriv.getCrtCoefficient()
);
ContentSigner contentSigner = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(rsaPrivParams);
final X509CertificateHolder x509CertificateHolder = certBuilder.build(contentSigner);
byte[] tbsCertDER = x509CertificateHolder.toASN1Structure().getTBSCertificate().getEncoded();
byte[] signature = x509CertificateHolder.getSignature();
return new TBSCertPlusSignature(tbsCertDER, signature);
}
private static X509Certificate generateCert(byte[] tbsCertEncoded, byte[] signature) throws Exception {
// Given the der encoded TBS cert and signature, create the corresponding X509 certificate
TBSCertificate tbsCert = TBSCertificate.getInstance(tbsCertEncoded);
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(tbsCert);
v.add(tbsCert.getSignature());
v.add(new DERBitString(signature));
DERSequence derSequence = new DERSequence(v);
ByteArrayInputStream baos = new ByteArrayInputStream(derSequence.getEncoded());
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(baos);
}
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair keyPair = kpg.generateKeyPair();
TBSCertPlusSignature testData = makeTestCert(keyPair);
X509Certificate x509Cert = generateCert(testData.getEncodedTbsCert(), testData.getSignature());
// Verify the signature
x509Cert.verify(keyPair.getPublic());
// Print the cert
PublicKey publicKey = x509Cert.getPublicKey();
System.out.println(x509Cert);
}
}

NoClassDefFoundError when calling function from RESTful web service

I'm trying to create a RESTful web service in java that will allow authentication with a Yubikey.
I'm modifying an existing tutorial that I completed while trying to learn about REST.
I'm trying to call the validation function from within the javax.ws.rs.core.Response function but keep getting an error with a package from the imported yubikey jars.
I imported these jars from build path -> libraries --> Add external Jars
Error as follows when I post my form to the RESTful url:
java.lang.NoClassDefFoundError: com/yubico/client/v2/exceptions/YubicoValidationException
package de.vogella.jersey.todo.resources;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import com.yubico.client.v2.exceptions.YubicoValidationException;
import com.yubico.client.v2.exceptions.YubicoValidationFailure;
import de.vogella.jersey.todo.resources.Validate;
#Path("/test")
public class Test {
#POST
public Response testCred(#FormParam("username") String username,
#FormParam("password") String password,
#FormParam("otp") String otp) throws YubicoValidationException, YubicoValidationFailure {
int client_id = 11095;
boolean status;
status = Validate.validate(otp, client_id);
return Response.status(200)
.entity("validation status: : " + status + ", for client " + otp)
.build();
}
}
the validate class is as follows:
package de.vogella.jersey.todo.resources;
import com.yubico.client.v2.YubicoClient;
import com.yubico.client.v2.YubicoResponse;
import com.yubico.client.v2.YubicoResponseStatus;
import com.yubico.client.v2.exceptions.YubicoValidationException;
import com.yubico.client.v2.exceptions.YubicoValidationFailure;
public class Validate {
public static boolean validate(String otp, int client_id) throws YubicoValidationException, YubicoValidationFailure {
YubicoClient client = YubicoClient.getClient(client_id);
YubicoResponse response = client.verify(otp);
if(response != null && response.getStatus() == YubicoResponseStatus.OK) {
return true;
}
return false;
}
}