play framework session returns wrong value with sha256 - session

I am having a problem with the session in play framework 1.2.4. When I add a SHA256-hash of a particular String ("testDude5") to the session and retrieve it afterwards, the values are not the same. It doesn't happen with other Strings like "testDude1". Here is the sample code to reproduce the result.
package controllers;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import play.mvc.Controller;
public class ExampleController extends Controller
{
public static final String test1 = "testDude1";
public static final String test2 = "testDude5";
public static void set()
{
session.put("test1", getHash(test1));
session.put("test2", getHash(test2));
}
public static void get()
{
String output = "";
output += "Test 1 compare: ";
output += session.get("test1").equals(getHash(test1)) ? "success" : "failed";
output += "\n";
output += "Test 2 compare: ";
output += session.get("test2").equals(getHash(test2)) ? "success" : "failed";
output += "\n";
renderText(output);
}
/**
* Generates the hash value for a password.
*
* #param password
* #return hash
*/
public static String getHash(String password)
{
// Create an digest object
MessageDigest md;
try
{
// Try to get sha-265
md = MessageDigest.getInstance("SHA-256");
// Encrypt the password
md.update(password.getBytes("UTF-8"));
// Get the encrypted password
byte[] digest = md.digest();
// Convert byte array to String
String str = new String(digest);
// Return encrypted password
return str;
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
return null;
}
}
I am totally puzzled by this. Does anyone have an idea whats going on there. Thanks for any advice.
Cheers

The problem is in your getHash function. There is nothing wrong with play framework session.
public static String getHash(String password) {
....
// Get the encrypted password
byte[] digest = md.digest();
// Convert byte array to String
String str = new String(digest); // DON'T do this with digest!
// The behavior is unspecified.
According to Java API doc, this constructor "Constructs a new String by decoding the specified array of bytes using the platform's default charset...The behavior of this constructor when the given bytes are not valid in the default charset is unspecified". However your hash digest may contains something not valid in the default charset.
Play framework provides a nice utility function Codec.byteToHeString() to transform digest in byte[] into hex string. This might be just what you need.
// Codec resides in play.libs
String str = Codec.byteToHexString(digest);

Related

How to read numeric value from excel file using spring batch excel

I am reading values from .xlsx using spring batch excel and POI. I see numeric values are printing with different format than the original value in .xlsx
Please suggest me , How to print the values as its in .xlsx file. Below are the details.
In my Excel values are as follows
The values are printing as below
My code is as below
public ItemReader<DataObject> fileItemReader(InputStream inputStream){
PoiItemReader<DataObject> reader = new PoiItemReader<DataObject>();
reader.setLinesToSkip(1);
reader.setResource(new InputStreamResource(DataObject));
reader.setRowMapper(excelRowMapper());
reader.open(new ExecutionContext());
return reader;
}
private RowMapper<DataObject> excelRowMapper() {
return new MyRowMapper();
}
public class MyRowMapper implements RowMapper<DataObject> {
#Override
public DataRecord mapRow(RowSet rowSet) throws Exception {
DataObject dataObj = new DataObject();
dataObj.setFieldOne(rowSet.getColumnValue(0));
dataObj.setFieldTwo(rowSet.getColumnValue(1));
dataObj.setFieldThree(rowSet.getColumnValue(2));
dataObj.setFieldFour(rowSet.getColumnValue(3));
return dataObj;
}
}
I had this same problem, and its root is the class org.springframework.batch.item.excel.poi.PoiSheet inside PoiItemReader.
The problem happens in the method public String[] getRow(final int rowNumber) where it gets a org.apache.poi.ss.usermodel.Row object and convert it to an array of Strings after detecting the type of each column in the row. In this method, we have the code:
switch (cellType) {
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
cells.add(String.valueOf(date.getTime()));
} else {
cells.add(String.valueOf(cell.getNumericCellValue()));
}
break;
case BOOLEAN:
cells.add(String.valueOf(cell.getBooleanCellValue()));
break;
case STRING:
case BLANK:
cells.add(cell.getStringCellValue());
break;
case ERROR:
cells.add(FormulaError.forInt(cell.getErrorCellValue()).getString());
break;
default:
throw new IllegalArgumentException("Cannot handle cells of type '" + cell.getCellTypeEnum() + "'");
}
In which the treatment for a cell identified as NUMERIC is cells.add(String.valueOf(cell.getNumericCellValue())). In this line, the cell value is converted to double (cell.getNumericCellValue()) and this double is converted to String (String.valueOf()). The problem happens in the String.valueOf() method, that will generate scientific notation if the number is too big (>=10000000) or too small(<0.001) and will put the ".0" on integer values.
As an alternative to the line cells.add(String.valueOf(cell.getNumericCellValue())), you could use
DataFormatter formatter = new DataFormatter();
cells.add(formatter.formatCellValue(cell));
that will return to you the exact values of the cells as a String. However, this also mean that your decimal numbers will be locale dependent (you'll receive the string "2.5" from a document saved on an Excel configured for UK or India and the string "2,5" from France or Brazil).
To avoid this dependency, we can use the solution presented on https://stackoverflow.com/a/25307973/9184574:
DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMaximumFractionDigits(340);
cells.add(df.format(cell.getNumericCellValue()));
That will convert the cell to double and than format it to the English pattern without scientific notation or adding ".0" to integers.
My implementation of the CustomPoiSheet (small adaptation on original PoiSheet) was:
class CustomPoiSheet implements Sheet {
protected final org.apache.poi.ss.usermodel.Sheet delegate;
private final int numberOfRows;
private final String name;
private FormulaEvaluator evaluator;
/**
* Constructor which takes the delegate sheet.
*
* #param delegate the apache POI sheet
*/
CustomPoiSheet(final org.apache.poi.ss.usermodel.Sheet delegate) {
super();
this.delegate = delegate;
this.numberOfRows = this.delegate.getLastRowNum() + 1;
this.name=this.delegate.getSheetName();
}
/**
* {#inheritDoc}
*/
#Override
public int getNumberOfRows() {
return this.numberOfRows;
}
/**
* {#inheritDoc}
*/
#Override
public String getName() {
return this.name;
}
/**
* {#inheritDoc}
*/
#Override
public String[] getRow(final int rowNumber) {
final Row row = this.delegate.getRow(rowNumber);
if (row == null) {
return null;
}
final List<String> cells = new LinkedList<>();
final int numberOfColumns = row.getLastCellNum();
for (int i = 0; i < numberOfColumns; i++) {
Cell cell = row.getCell(i);
CellType cellType = cell.getCellType();
if (cellType == CellType.FORMULA) {
FormulaEvaluator evaluator = getFormulaEvaluator();
if (evaluator == null) {
cells.add(cell.getCellFormula());
} else {
cellType = evaluator.evaluateFormulaCell(cell);
}
}
switch (cellType) {
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
cells.add(String.valueOf(date.getTime()));
} else {
// Returns numeric value the closer possible to it's value and shown string, only formatting to english format
// It will result in an integer string (without decimal places) if the value is a integer, and will result
// on the double string without trailing zeros. It also suppress scientific notation
// Regards to https://stackoverflow.com/a/25307973/9184574
DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMaximumFractionDigits(340);
cells.add(df.format(cell.getNumericCellValue()));
//DataFormatter formatter = new DataFormatter();
//cells.add(formatter.formatCellValue(cell));
//cells.add(String.valueOf(cell.getNumericCellValue()));
}
break;
case BOOLEAN:
cells.add(String.valueOf(cell.getBooleanCellValue()));
break;
case STRING:
case BLANK:
cells.add(cell.getStringCellValue());
break;
case ERROR:
cells.add(FormulaError.forInt(cell.getErrorCellValue()).getString());
break;
default:
throw new IllegalArgumentException("Cannot handle cells of type '" + cell.getCellTypeEnum() + "'");
}
}
return cells.toArray(new String[0]);
}
private FormulaEvaluator getFormulaEvaluator() {
if (this.evaluator == null) {
this.evaluator = delegate.getWorkbook().getCreationHelper().createFormulaEvaluator();
}
return this.evaluator;
}
}
And my implementation of CustomPoiItemReader (small adaptation on original PoiItemReader) calling CustomPoiSheet:
public class CustomPoiItemReader<T> extends AbstractExcelItemReader<T> {
private Workbook workbook;
#Override
protected Sheet getSheet(final int sheet) {
return new CustomPoiSheet(this.workbook.getSheetAt(sheet));
}
public CustomPoiItemReader(){
super();
}
#Override
protected int getNumberOfSheets() {
return this.workbook.getNumberOfSheets();
}
#Override
protected void doClose() throws Exception {
super.doClose();
if (this.workbook != null) {
this.workbook.close();
}
this.workbook=null;
}
/**
* Open the underlying file using the {#code WorkbookFactory}. We keep track of the used {#code InputStream} so that
* it can be closed cleanly on the end of reading the file. This to be able to release the resources used by
* Apache POI.
*
* #param inputStream the {#code InputStream} pointing to the Excel file.
* #throws Exception is thrown for any errors.
*/
#Override
protected void openExcelFile(final InputStream inputStream) throws Exception {
this.workbook = WorkbookFactory.create(inputStream);
this.workbook.setMissingCellPolicy(Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
}
}
just change your code like this while reading data from excel.
dataObj.setField(Float.valueOf(rowSet.getColumnValue(idx)).intValue();
this is only working for Column A,B,C

How to obtain the same lenght string encoding with Blowfish+Hex

We're trying to encode several input strings with the same length (32) applying Blowfish + Hex encoding.
The problem is that not always the final coded strings have the same length as we expect (32 length strings).
Below you find the code used. Please, can you help to suggest what's wrong?
public static String encrypt(String clear, String key)
{
try
{
Security.setProperty("crypto.policy", "unlimited");
byte [] keyBytes = key.getBytes("ASCII");//toByteArray(key);
filelogger.info("Key coded in bytes "+keyBytes);
SecretKeySpec skey = new SecretKeySpec(keyBytes, "Blowfish");
byte [] clearBytes = clear.getBytes();//toByteArray(clear);
filelogger.info("Input string coded in bytes "+clearBytes);
Cipher ci = Cipher.getInstance("Blowfish");
ci.init(Cipher.ENCRYPT_MODE, skey);
// encrypt the clear bytes value
byte[] encoded = ci.doFinal(clearBytes);
filelogger.info("Blowfish output "+encoded);
return Base64.getEncoder().encodeToString(encoded);
}
catch (Exception e)
{
filelogger.error("Error while encrypting: " + e.toString());
logger.error("Error while encrypting: " + e.toString());
return Base64.getEncoder().encodeToString(new byte[0]);
}
}
Best regards
We have solved using the following solution:
Passing the option "Blowfish/ECB/NoPadding" to the getInstance function.
public byte[] encryptBlowfishECBNopadding(byte[] key, byte[] dati) {
byte[] output = null;
try {
SecretKeySpec KS = new SecretKeySpec(key, "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, KS);
output = cipher.doFinal(dati);
return output;
} catch (Exception ee) {
logger.error(ee.getMessage());
filelogger.error(ee.toString());
return new byte[0];
}
}
Encoding the result of the method as below:
byte[] encryptresult=encryptBlowfishECBNopadding(toByteArray(decriptedki),toByteArray(criptokeyhlr.getKeydata()));
String stringencriptedki=Hex.encodeHexString(encryptresult).toUpperCase();
In this manner every output string has the same length.
Thanks to all for the support!

Web API error response Id

I have an error response model in my API project:
public class ErrorResponse
{
public string ErrorId { get; set;}
public string Message {get; set;}
}
I need to generate a random ErrorId. I saw the use of Random class but just wondering what is the best way to do this. Some consideration, do I need to create the ErrorId in the constructor of ErrorResponse class and make ErrorId as read-only (no setter) or do I let the ErrorId set by the calling class.
You can create a new Guid and assign it to ErrorId in the constructor:
public ErrorResponse()
{
ErrorId = Guid.NewGuid().ToString();
}
Alternatively, you may want to give the client an http response and include the ErrorId:
return Content(HttpStatusCode.BadRequest, "ErrorId");
You can use the Random class or generate a Guid. But I just want to expand on what I think you are trying to do. Instead of your own custom error response - perhaps considering using the HttpResponseException or the HttpResponseMesssage. You can include a custom / random error identifier in Content / reason or in the message.
public IEnumerable<string> Get()
{
try
{
SomeMethod();
return new string[] { "xxx", "yyy" };
}
catch (Exception e)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("An error occurred."),
ReasonPhrase = "your custom error id"
});
// log
}
}
And:
public HttpResponseMessage Get(int id)
{
try
{
// your code
}
catch (Exception ex)
{
// Log exception code goes here
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "your custom error id.”);
}
}
Best way to create Random number is to use Random class in C#... Here is the example
Random rnd = new Random();
int first = rnd.Next(1, 40); //Number between 1(inclusive) and 40(exclusive)
int second = rnd.Next(10); //Number between 0 and 9
Note: If you are going to create more than one random numbers then you should use the same instance of the Random class. If you create new instance too close in time, there are chances that they both will produce the same random numbers as Random class is based(seeded)on System clock.
I use Random but quite not sure if there are consequences in an API application(due to thread-safety, etc). So in the constructor, I generate the ErrorId.
public ErrorResponse()
{
var random = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890.!+-?";
ErrorId = new string(Enumerable.Repeat(chars, 10)
.Select(s => s[random.Next(s.Length)]).ToArray());
}

I am trying to use a function that uses FormatWith() and I get an error in C#

I am trying to build an email template. I got what is suppose to be working example but I am having problems trying to get FormatWith() to resolve in one of the functions.
private static string PrepareMailBodyWith(string templateName, params string[] pairs)
{
string body = GetMailBodyOfTemplate(templateName);
for (var i = 0; i < pairs.Length; i += 2)
{
// wonder if I can bypass Format with and just use String.Format
body = body.Replace("<%={0}%>".FormatWith(pairs[i]), pairs[i + 1]);
//body = body.Replace("<%={0}%>",String.Format(pairs[i]), pairs[i + 1]);
}
return body;
}
It looks like an extension method to me.
You need to reference the namespace the extension method lives in at the top of your file.
Example:
namespace MyApp.ExtensionMethods
{
public class MyExtensions
{
public static string FormatWith(this string target, params object[] args)
{
return string.Format(Constants.CurrentCulture, target, args);
}
}
}
...
using MyApp.ExtensionMethods;
...
private static string PrepareMailBodyWith(string templateName, params string[] pairs)
{
string body = GetMailBodyOfTemplate(templateName);
for (var i = 0; i < pairs.Length; i += 2)
{
// wonder if I can bypass Format with and just use String.Format
body = body.Replace("<%={0}%>".FormatWith(pairs[i]), pairs[i + 1]);
//body = body.Replace("<%={0}%>",String.Format(pairs[i]), pairs[i + 1]);
}
return body;
}
Try using String.Format() instead, like you suggested...
body = body.Replace(String.Format("<%={0}%>", pairs[i]), String.Format("<%={0}%>", pairs[i+1]);
This assumes you want both the search string and the replacement string to be formatted.
I found it was easier to use the .Replace() then to jump through all the other hoops. Thank you for your suggestions.
string email = emailTemplate
.Replace("##USERNAME##", userName)
.Replace("##MYNAME##", myName);
This seems to be the simplest solution to my email template issue.

Hashmap value changed after requesting from session

I work on Java/HTML project. I've set a hashmap as a session attribute. I request the hashmap from session and put key/value in it
map.put("some string", "1")
. When this action is performed the second time, I print the hashmap content and the only value, that was '1' after the last operation on the hashmap, becomes '-1'.
Hashmap is the best data structure, in my opinion, for this project. Can anyone help?
public class Cart {
private HashMap<String, asd> list;
public Cart(){
list = new HashMap<String, asd>();
}
public HashMap<String, asd> getMap(){
return list;
}
/*
* Parameter: code
* -1: increase quantity by 1
* 0: delete product from the product list
* else: set the product quantity to the passed value
*/
public void alterProduct(int code, String product){
if(list.containsKey(product)) {
if(code == -1) plusOne(product);
if(code == 0) remove(product);
else setValue(product, code);
}else {
asd asd = new asd();
asd.a = 1;
list.put(product, asd);
}
}
private void plusOne(String product){
asd asd = list.get(product);
asd.a = asd.a + 1;
list.put(product, asd);
}
private void remove(String product){
list.remove(product);
}
private void setValue(String product, int code){
asd asd = new asd();
asd.a = code;
list.put(product, asd);
}
}
class asd{
int a;
public String toString(){
return ""+a;
}
}
JSP code where I set Cart object as session attribute:
<%
Cart myCart = new Cart();
session.setAttribute("cart",myCart);
%>
Servlet code:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
Cart cart = (Cart) request.getSession().getAttribute("cart");
cart.alterProduct(-1, (String) request.getSession().getAttribute("name"));
doGet(request, response);
}
After I call alterProduct the second time for the same (String) request.getSession().getAttribute("name") the hashmap value for the same key is '-1'.
What is type/value of product? How it is connected to the "cart"?
I guess what's happen that you mess up data types. Another option is you have bug in the Cart.toString() method. I suggest you change the code with "plain" data type and recheck it. If it fails, use your Cart class without messy conversion and debug the code.
You have bug here:
public void alterProduct(int code, String product){
if(list.containsKey(product)) {
if(code == -1) plusOne(product);
if(code == 0) remove(product);
else setValue(product, code);
}
private void setValue(String product, int code){
asd asd = new asd();
asd.a = code;
list.put(product, asd);
}
Consider what happen when you call art.alterProduct(-1, "something") second time.
list.containsKey(product) is true (you use the same product"), code is -1. So
if(code == -1) plusOne(product); is executed as expected.
But then you have something weired
if(code == 0) remove(product);
else setValue(product, code);
code ==0 is evaluated to false, so else instruction is called. You are calling setValue(product, -1)
As you can see above setValue will assign -1 to the asd.a that is observed by you.

Resources