JWT signing with public and private key - spring

I have written this portion of code to create a JWT.
public String createJWT() throws JoseException {
RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
// Give the JWK a Key ID (kid), which is just the polite thing to do
rsaJsonWebKey.setKeyId(keyId);
// Create the Claims, which will be the content of the JWT
JwtClaims claims = new JwtClaims();
claims.setIssuer(issuer);
claims.setExpirationTimeMinutesInTheFuture(60);
claims.setJwtId(keyId);
claims.setIssuedAtToNow();
claims.setNotBeforeMinutesInThePast(2);
claims.setSubject(subject);
// We create a JsonWebSignature object.
JsonWebSignature jws = new JsonWebSignature();
// The payload of the JWS is JSON content of the JWT Claims
jws.setPayload(claims.toJson());
//The header of the JWS
jws.setHeader("typ", "JWT");
// The JWT is signed using the private key
jws.setKey(rsaJsonWebKey.getPrivateKey());
jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId());
// Set the signature algorithm on the JWT/JWS that will integrity protect the claims
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
// Sign the JWS and produce the compact serialization or the complete JWT/JWS
// representation, which is a string consisting of three dot ('.') separated
// base64url-encoded parts in the form Header.Payload.Signature
String jwt = jws.getCompactSerialization();
System.out.println("JWT: " + jwt);
return jwt;
}
But I don't understand which private key is it retrieving? How can I customize this code to send my own public and private key stored in local JKS??
Thanks in advancee!!

Try to use the following to load your own keystore:
try (InputStream is = new FileInputStream(new File("path to keystore"))) {
KeyStore keyStore = KeyStore.getInstance(ksType);
keyStore.load(is, password);
final Enumeration<String> aliases = keyStore.aliases();
final String alias = aliases.nextElement(); // assuming only one entry
final Entry entry = keyStore.getEntry(alias, password);
if (entry instanceof PrivateKeyEntry) {
PrivateKeyEntry pke = (PrivateKeyEntry) entry;
PrivateKey privateKey = pke .getPrivateKey();
// and here you may return the PrivateKey
}
} catch (Exception e) {
...
}
Disclaimer : I did not test the code, but it should work.

Related

why we need to do sever side validation for google recaptcha?

In my new project, I am going to include google recaptcha.
my question is fairly simple even if we do client side validation that user is not a robot even though it is suggested to do server side validation.
I want to know why it is necessary to do server side validation for google recaptcha? how does it add the extra layer of security? and how to do in spring boot with spring security?
Server side validation is MUST !! reCAPTCHA is designed in a way that client side just generates the 'g-captcha-response' which along with secret key (stored at server-side) is sent to https://www.google.com/recaptcha/api/siteverify for validation. The response is a JSON which states sucesss true or false and it is further pushed to client side. Validating only at the client side is technically possible, but it defeats the purpose. Moreover, you may get CORS (Cross-Origin Resource Sharing) policy error in console if you do only client side validation. I can share steps to do simple java based server side validation in servlet. Let me know if you need that.
Here is the code. Few points to be noted:
The parameter userResponse = request.getParameter("recaptchaResponse") is the way by which i am getting the 'g-recaptcha-response' generated by the user when he clicked reCAPTCHA widget on UI. On your javascript, capture the value of field 'g-recaptcha-response' and pass it appended to request. Then in servlet, we can get it from request.getParameter.
Sample code:
var recaptchaResponse = document.getElementById("g-recaptcha-response").value;
//alert("g-recaptcha-response= "+recaptchaResponse);
if (recaptchaResponse.length > 0)
{
var xmlhttp1;
if (window.XMLHttpRequest)
{
xmlhttp1=new XMLHttpRequest();
}
else
{
xmlhttp1=new ActiveXObject("Microsoft.XMLHTTP");
}
var query1 = "?recaptchaResponse=" + recaptchaResponse;
xmlhttp1.open("POST","captchaVerificationServlet" + query1, false);
xmlhttp1.send(null);
var resp1 = xmlhttp1.responseText;
alert("resp1= "+resp1);
if(resp1=='matched'){
return true;
}
else{
alert("resp1 did not match");
return false;
}
}
else{
alert("error: recaptcha response is blank");
return false;
}
For simplicity i am checking presence of "success:true" in returned JSON response. As you know, returned JSON contains two parameters : success and error-codes. You may use a JSONReader to read and parse JSON and obtain all parameters fully. Sample code will be like
JsonReader rdr = Json.createReader(your_inputstream);
JsonObject jsonObject = rdr.readObject();
Needless to say, remove all alerts and sop statements in production!
public class CaptchaVerificationServlet extends HttpServlet {
private static final String sec = YOUR_SECRET_KEY;
public void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String userResponse = request.getParameter("recaptchaResponse");
response.setCharacterEncoding("UTF-8");
System.out.println("userResponse= "+userResponse);
//verify user response with Google ReCaptcha API
String ipAddress = request.getRemoteAddr(); //get client's ip address
System.out.println("ipAddress= "+ipAddress);
try{
String s = validateCaptcha(sec, userResponse, ipAddress);
Boolean success = (s.contains("\"success\": true"));
if(success)
response.getWriter().write("matched");
}
catch(Exception ioe){
ioe.printStackTrace();
ioe.printStackTrace(response.getWriter());
}
}
private String validateCaptcha(String secret, String response, String remoteip) throws IOException
{
URLConnection connection = null;
InputStream is = null;
String output = "";
String proxyHost = "YOUR_PROXY_NAME";
int proxyPort = 80; //proxy server port, generally 80 or 443 (confirm from sys-admin)
SocketAddress addr = new InetSocketAddress(proxyHost, proxyPort);
Proxy httpProxy = new Proxy(Proxy.Type.HTTP, addr);
String filename = System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar);
String password = "changeit";
System.setProperty("javax.net.ssl.trustStore",filename);
System.setProperty("javax.net.ssl.trustAnchors",filename);
System.setProperty("javax.net.ssl.trustStorePassword",password);
String charset = Charset.forName("UTF-8").name();
String url = "https://www.google.com/recaptcha/api/siteverify";
try {
String query = String.format("secret=%s&response=%s&remoteip=%s",
URLEncoder.encode(secret, charset),
URLEncoder.encode(response, charset),
URLEncoder.encode(remoteip, charset));
URL fullURL = new URL(url + "?" + query);
connection = fullURL.openConnection(httpProxy);
connection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0");
is = connection.getInputStream();
System.out.println("connection InputStream");
BufferedReader reader = null;
String responseXXX = "";
reader = new BufferedReader(new InputStreamReader(is));
responseXXX = reader.readLine();
while (responseXXX!=null) {
output+= responseXXX;
responseXXX = reader.readLine();
}
System.out.println("Output: " + output);
}
finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
//cannot do anything here
}
}
}
return output;
}
}

How to store additional data per user like session on Owin using Bearer Token

I need to store a token for thirdy party software calls on my controller after my client sign in, so I tried to save this on User Claims:
public class BaseController : ApiController
{
private const string Token = "thirdyparty.token";
private string Token
{
set
{
// Here I want to store a token in any way (Session, Cache, etc)
var claimsIdentity = (ClaimsIdentity)User.Identity;
var claims = claimsIdentity.Claims;
var tokenClaim = claims.FirstOrDefault(x => x.Type == Token);
if (Token != null)
{
claimsIdentity.RemoveClaim(tokenClaim);
}
claimsIdentity.AddClaim(new Claim(Token, value));
}
get
{
// Here I want to get the token
var claimsIdentity = (ClaimsIdentity)User.Identity;
var claims = claimsIdentity.Claims;
var tokenClaim = claims.FirstOrDefault(x => x.Type == Token);
return tokenClaim?.Value;
}
}
}
This did not work, my new Claim disappeared every time a new request is made.
So, how can I store some additional information per user?
The problem is that the claims are part of the bearer token.
So even if you add the claim to the current identity the next request will
have the old claim values as they are part of the token sent with the new request.
So, if you add a claim you need to generate a new token as well and return that to the client.
One way to generate a new token is to store the OAuthAuthorizationServerOptions, used in the
Startup.cs class, as a static variable and then use that where it's needed
public class Startup
{
public static OAuthAuthorizationServerOptions OAuthServerOptions { get; private set; }
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
//....add the rest
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AuthProvider() //Your derived OAuthAuthorizationServerProvider
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
Then to generate a new token
var claimsIdentity = ... //The claim identity after you have added the new claims
var newToken = Startup.OAuthServerOptions.AccessTokenFormat.Protect(new AuthenticationTicket(claimsIdentity, new AuthenticationProperties()));

Json web token in Web api not validating the refresh token after its expiry

I am using JWT authentication for WEB API using OAuth 2. I am using Refresh tokens mechanism. I am able to generate the refresh token and call API service from it before the expiration time. Once the token is expired , i am calling service to issue new token using refresh token id. But its giving error in my CustomJWTFormat class UnProtect method as it not implement any logic. I am not getting what logic to be implemented to reissue JWT refresh token.
Sample codes for configuring serviec to use JSON web token format:
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(5),
Provider = new SimpleAuthorizationServerProvider(),
RefreshTokenProvider = new SimpleRefreshTokenProvider(),
AccessTokenFormat = new CustomJwtFormat(<issuer>),
RefreshTokenFormat = new CustomJwtFormat(<issuer>)
};
Sample code of my CustomJWTFormat class:
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private const string AudiencePropertyKey = "as:client_id";
private readonly string _issuer = string.Empty;
private string symmetricKeyAsBase64 = string.Empty;
public CustomJwtFormat(string issuer)
{
_issuer = issuer;
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
string audienceId = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null;
if (string.IsNullOrWhiteSpace(audienceId))
{
audienceId = <audience>;
symmetricKeyAsBase64 = <secret key>;
}
else
{
using (AuthRepository _repo = new AuthRepository())
{
var audience = _repo.FindClient(audienceId);
symmetricKeyAsBase64 = audience.Secret;
}
}
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
///Need logic for this method. Its calling when service is called to generated new token for refresh id
public AuthenticationTicket Unprotect(string protectedText)
{
throw NotImplementedException();
}
}
}
Any help will be appreciated.
Have a look at this sample to give you an idea of validating a token.
https://github.com/AzureADSamples/WebAPI-ManuallyValidateJwt-DotNet/blob/master/TodoListService-ManualJwt
In particular, Global.asax.cs.

Unable to sign text block with Private Key

I am trying to create a digital signature of a load of clipboard text. I am:
Creating a SHA-256 hash of the plain text.
Encrypting this hash with my PRIVATE key.
Attempting to decrypt this with my PUBLIC key.
I'm doing this as I am of the understanding that anything signed with my PRIVATE key can be decrypted with my PUBLIC - such as this for verification? Is this wrong?
I'm encrypting the hash with these methods:
public static string EncryptText(string text, int keySize, string publicKey)
{
var encrypted = Encrypt(Encoding.UTF8.GetBytes(text), keySize, publicKey);
return Convert.ToBase64String(encrypted);
}
public static byte[] Encrypt(byte[] data, int keySize, string publicKeyXml)
{
if (data == null || data.Length == 0) throw new ArgumentException("Data are empty", "data");
int maxLength = GetMaxDataLength(keySize);
if (data.Length > maxLength) throw new ArgumentException(String.Format("Maximum data length is {0}", maxLength), "data");
if (!IsKeySizeValid(keySize)) throw new ArgumentException("Key size is not valid", "keySize");
if (String.IsNullOrEmpty(publicKeyXml)) throw new ArgumentException("Key is null or empty", "publicKeyXml");
using (var provider = new RSACryptoServiceProvider(keySize))
{
provider.FromXmlString(publicKeyXml);
return provider.Encrypt(data, OptimalAsymmetricEncryptionPadding);
}
}
but passing my PRIVATE KEY down instead of my PUBLIC KEY.
Then to verify the signature, I am using:
public static string DecryptText(string privateKey, int keySize, string text)
{
var decrypted = Decrypt(Convert.FromBase64String(text), keySize, privateKey);
return Encoding.UTF8.GetString(decrypted);
}
public static byte[] Decrypt(byte[] data, int keySize, string publicAndPrivateKeyXml)
{
if (data == null || data.Length == 0) throw new ArgumentException("Data are empty", "data");
if (!IsKeySizeValid(keySize)) throw new ArgumentException("Key size is not valid", "keySize");
if (String.IsNullOrEmpty(publicAndPrivateKeyXml)) throw new ArgumentException("Key is null or empty", "publicAndPrivateKeyXml");
using (var provider = new RSACryptoServiceProvider(keySize))
{
provider.FromXmlString(publicAndPrivateKeyXml);
return provider.Decrypt(data, OptimalAsymmetricEncryptionPadding);
}
}
but passing down my PUBLIC KEY rather than the PRIVATE KEY. At this point, I am getting an error "Key does not exist".
I'm presuming this is the case because the PRIVATE KEY contains the relevant key information for the PUBLIC KEY so it can decode this one-way.
How can I sign a block of text in this way that allows me to distribute a signature with it, that can be decrypted by anybody who knows my PUBLIC KEY?
After much trawling, I found this page:
http://juzzbott.com.au/blog/signing-and-verifying-data-within-csharp

How to disable Subject Key Identifier in SecurityTokenResolver

I am processing a SAML2 token in WIF which contains an EncryptedAssertion. The mark-up does NOT contain a "Subject Identifier Key" Extension property and as such WIF SecurityTokenHandler fails as it tries to get the correct X509 certificate from the LocalMachineStore/Personal.
The issue is clearly that the certificate used to encrypt the token does not contain the SKI Extension and of course the token generation code (Java) does not do seem to require it. To avoid having to modify the generation code is there a way I can get WIF SecuityTokenResolver to NOT check the received Token for the SKI but simply use the local store certificate directly to decrypt the token?
In the end I just implemented a custom SecurityTokenResolver and implemented the TryResolveSecurityKeyCore method.
Here is the code:
public class mySaml2SSOSecurityTokenResolver : SecurityTokenResolver
{
List<SecurityToken> _tokens;
public PortalSSOSecurityTokenResolver(List<SecurityToken> tokens)
{
_tokens = tokens;
}
protected override bool TryResolveSecurityKeyCore(System.IdentityModel.Tokens.SecurityKeyIdentifierClause keyIdentifierClause, out System.IdentityModel.Tokens.SecurityKey key)
{
var token = _tokens[0] as X509SecurityToken;
var myCert = token.Certificate;
key = null;
try
{
var ekec = keyIdentifierClause as EncryptedKeyIdentifierClause;
if (ekec != null)
{
switch (ekec.EncryptionMethod)
{
case "http://www.w3.org/2001/04/xmlenc#rsa-1_5":
{
var encKey = ekec.GetEncryptedKey();
var rsa = myCert.PrivateKey as RSACryptoServiceProvider;
var decKey = rsa.Decrypt(encKey, false);
key = new InMemorySymmetricSecurityKey(decKey);
return true;
}
}
var data = ekec.GetEncryptedKey();
var id = ekec.EncryptingKeyIdentifier;
}
}
catch (Exception ex)
{
// Do something here }
return true;
}
protected override bool TryResolveTokenCore(System.IdentityModel.Tokens.SecurityKeyIdentifierClause keyIdentifierClause, out System.IdentityModel.Tokens.SecurityToken token)
{
throw new NotImplementedException();
}
protected override bool TryResolveTokenCore(System.IdentityModel.Tokens.SecurityKeyIdentifier keyIdentifier, out System.IdentityModel.Tokens.SecurityToken token)
{
throw new NotImplementedException();
}
}
}

Resources