#Override
public boolean validar(String login, String password) {
Map<String, Object> map = jdbcTemplate.queryForMap(queryPorLogin, login);
if(map.equals(password)) {
return true;
}else {
return false;
}
}
I'm wondering how I can do this password verification with the bcrypt method
BCrypt.checkpw(password, rs.getString("password"))
if(map.equals(password)) - this will internally compares two maps by comparing both entry set either they are same with same mapping or not. so map and string can never be equal.
So first get String pwd= map.get("password"); and
then check if(pwd!=null && pwd.equals(password))
Now coming to BCrypt Implementation:-
private final int logRounds=5; // It will be between 4 to 31
public String hash( #PathVariable("pwd") String password) {
return BCrypt.hashpw(password, BCrypt.gensalt(logRounds)); // You will Store Hash into database.
}
and for verification:-
BCrypt.checkpw(password, hash); // here hash value you will get from database
// password that user have entered
Although this is just basic example and can be included complex hashing strategies.
IMO it would be better if you will use BCryptPasswordEncoder.matches(CharSequence rawPassword, String encodedPassword) from spring-security module. Also this module has feature for checking password behid this scenes. You just need to dig a little bit for some tutorial.
Related
I'm trying to #Test a Service class but there are several get() methods that I don't know how to test. I would need to know how to collect the data that is necessary or at least how to test the rest of the methods of the TokenHelper class.
This is the Session class:
public class SessionData {
public static final String KEY = "session_data";
private Integer id;
private String email;
private String fullName;
private List<Role> role;
private Boolean tempSession;
private int permissionsMask = 0;
private String avatar;
public boolean hasAnyRole(Role... roles) {
for (Role r : roles) {
if (this.role.contains(r)) {
return true;
}
}
return false;
}
}
This is the TokenHelper class:
public class TokenHelper {
public String generate(SessionData tokenData, long expirationInHours) {
return Jwts.builder()
.claim(SessionData.KEY, tokenData)
.setIssuedAt(Date.from(Instant.now()))
.setExpiration(Date.from(Instant.now().plus(expirationInHours, ChronoUnit.HOURS)))
.signWith(SignatureAlgorithm.HS256, TextCodec.BASE64.encode(secret))
.compact();
}
public UserGoogle getTokenDataFromGoogleToken(String token) throws InvalidTokenException {
try {
int i = token.lastIndexOf('.');
String withoutSignature = token.substring(0, i + 1);
Claims claims = Jwts.parser().parseClaimsJwt(withoutSignature).getBody();
return UserGoogle.builder()
.email(claims.get(UserGoogle.KEY_EMAIL).toString())
.firstName(claims.get(UserGoogle.KEY_FIST_NAME).toString())
.lastName(claims.get(UserGoogle.KEY_LAST_NAME).toString()).build();
} catch (ExpiredJwtException | MalformedJwtException | SignatureException | IllegalArgumentException ex) {
log.error(ERROR_TOKEN, ex.toString());
throw new InvalidTokenException();
}
}
}
This is my #Test:
#Test
void googleTokenHelperTest() throws InvalidTokenException {
TokenHelper obj1 = BeanBuilder.builder(TokenHelper.class).createRandomBean();
String mailGoogle = "google#prueba.com";
String firstGoogle = "Nombre";
String lastGoogle = "Apellido";
Map<String, Object> pruebaGoogle = new HashMap<String, Object>();
List<String> info = new ArrayList<String>();
info.add(firstGoogle);
info.add(lastGoogle);
pruebaGoogle.put(mailGoogle, info);
UserGoogle expectedUser = UserGoogle.builder().email(mailGoogle).firstName(firstGoogle).lastName(lastGoogle).build();
String myTestToken = pruebaGoogle.toString();
UserGoogle actualUser = obj1.getTokenDataFromGoogleToken(myTestToken);
assertEquals(actualUser, expectedUser);
}
I have created some variables to form a user, but I need to build them with a map to generate the token with the help of the generate () method. I need to know how to join those three variables and pass them to the generate () method, and then pass the result variable to the google method to generate the new user.
Edit: After clarification by OP the topic of the question changed.
Your problem arises from a flawed Object-Orientation-Design. For example, your SessionData implicitly holds a User by having String-fields relevant to a User among fields relevant to a Session. This overlapping makes it hard to test your code, because in order to test your Token-Generation for some User data, you need a Session object, which introduces additional data and dependencies.
That is one major reason, why it's difficult for you, to get a token from your three input values.
You want to test getTokenDataFromGoogleToken(String token). First thing you need to know is, what a valid Token-String will look like.
Next, you will need to mock your Claims claims object in one of two ways:
Mockito.mock it using Mockito to return the necessary Strings when claims.get() is called.
Mockito.mock your Jwts.parser().parseClaimsJwt(withoutSignature).getBody() to return a Claims object that serves your testing purpose.
Since the signature of your token will be irrelevant to your tested method, just focus on the substring before the .-Separator, i.e. the part after . in your token string can be any string you like.
If you want to test generate(SessionData, long) you need to supply a SessionData Object and a long value. After that you assertEquals the String as necessary. However, currently your code does not imply that your get is in any way related to your generate. This is, because you just handle Strings. A better design would be to have e.g. a User, Session and Token-classes, which would also make it easier to test your application and units.
A Test for your getToken method looks like the following, you just have to replace ... with your test data.
#Test
void givenGoogleToken_whenTokenHelperGeneratesUserFromToken_UserOk() {
TokenHelper helper = new TokenHelper();
String myTestToken = ...; //
UserGoogle expectedUser = ... // generate the UserGoogle Object you expect to obtain from your TokenHelper class
UserGoogle actualUser = helper.getTokenDataFromGoogleToken(myTestToken);
assertEquals(actualUser, expectedUser);
}
Test generally follow a given-when-then structure. Given some precondition, when some action is performed, then some result is returned/behaviour observed. When implemented very formally, this is called BDD (Behaviour Driven Development), but even when not practicing BDD, tests still generally follow that pattern.
In this case, I would suggest the tests be something like:
Given some data exists in the service threaddata
when I call get
then I get back the expected value
In the scenario above, the given part probably consists of setting some data on the service, the when is invoking get and the then is asserting that it's the expected value.
And I'd encourage you to consider the various scenarios. E.g what happens if the data isn't there? what happens if it's not the class the consumer asks for? Is the map case-sensitive? etc...
Code sample for the initial instance (I'm not sure what BeanBuilder is here, so I've omitted it):
#Test
public void testCurrentThreadServiceReturnsExpectedValue() {
final String key = "TEST KEY";
final String value = "TEST VALUE";
//Initialize System Under Test
CurrentThreadService sut = new CurrentThreadService();
//Given - precondition
sut.set(key, value);
//When - retrieve value
String observedValue = sut.get(key, String.class);
//Then - value is as expected
assertEquals(value, observedValue);
}
EDIT TO ADD It's always great to see someone get into unit testing, so if you have any follow ups, please ask I'm happy to help. The confidence one derives from well tested code is a great thing for software devs.
I have a method that fetches all the data and i am caching the result of that method but i am not able to evict the result.
#Component("cacheKeyGenerator")
public class CacheKeyGenerator implements KeyGenerator {
#Override
public Object generate(Object target, Method method, Object... params) {
final List<Object> key = new ArrayList<>();
key.add(method.getDeclaringClass().getName());
return key;
}
}
CachedMethod:-
#Override
#Cacheable(value="appCache",keyGenerator="cacheKeyGenerator")
public List<Contact> showAllContacts() {
return contactRepository.findAll();
}
#Override
#CachePut(value="appCache",key="#result.id")
public Contact addData(Contact contact) {
return contactRepository.save(contact);
}
Now when ever addData is called i want the data in the cache "appCache" with the key ="cacheKeyGenerator" to be evicted.So that the data returned by the method "showAllContacts()" is accurate.Can anyone please help!
The Entire code can be found at - https://github.com/iftekharkhan09/SpringCaching
Assuming you have a known constant cache key for showAllContacts then the solution should be to simply add #CacheEvict on addData passing in the cache name and key value:
#Override
#Caching(
put = {#CachePut(value="appCache", key="#result.id")},
evict = {#CacheEvict(cacheNames="appCache", key="someConstant")}
)
public Contact addData(Contact contact) {
return contactRepository.save(contact);
}
However because you use a key generator it is a bit more involved. Now given what your key generator does, you could instead pick a value for that cache key, making sure there can't be any collisions with the values from #result.id and use that value instead of a the key generator returned one.
I just want to disable cache for users that are admins. So I write a method to generate keys as below that returns null for admins. But I get
java.lang.IllegalArgumentException: Null key returned for cache
operation
exeption.
Is there any way achieve that?
//a method that generates a menu for each user
#Cacheable(cacheNames = "topmenu", keyGenerator = "uiComponentKey")
#Override
public String renderResponse() {...}
//method used by a key generator to generate cache keys.
#Override
public Object getCacheKey() {
if (user.isAdmin()) {
return null;
}
return user.getUser().getLogin() + "#" + "topmenu";
}
I guess you can achive that using conditional caching feature. Smth like this:
#Cacheable(cacheNames = "topmenu", condition="#user.isAdmin()")
#Override
public String renderResponse(User user) {...}
Note, that you're going to have to pass user object to this method in this case.
I have a web application which uses Spring MVC. Is it possible that controller return temporary view depending on condition ? For example
#RequestMapping(value="/")
public String home(){
// some code here
return "home/{RANDOM_HASH}"
}
and user is redirected to this link. There is some action and when it finishes, he will be redirected somewhere else and he will not be able to connect to this even if he write full path, including random hash.
English isn’t my first language, so please excuse any mistakes.
Yes, you can use #PathVariable to bind HTTP parameters to method arguments:
#RequestMapping(value="home/{hash}")
public String link(#PathVariable String hash) {
// 1) verify hash was not made up
// 2) do whatever needs done with hash
return "somewhereElse";
}
As to how to verify the hash was really created by your application and not typed in the URL bar: you can create some sort of "token manager". It would manage all hashes: issue new tokens and invalidate old ones once they're used. Simplified implementation could be something like this:
#NotThreadSafe
class TokenService {
private final Set<String> hashes = new HashSet<String>();
public String getHash() {
String hash = "???"; // TODO: random generator
hashes.put(hash);
return hash;
}
public void invalidateHash(String hash) {
hashes.remove(hash);
}
public boolean checkHash(String hash) {
return hashes.contains(hash);
}
}
Please note that real-life implementation should make access to hashes thread-safe.
I am doing a Spring web. For a controller method, I am able to use RequestParam to indicate whether a parameter it is required or not. For example:
#RequestMapping({"customer"})
public String surveys(HttpServletRequest request,
#RequestParam(value="id", required = false) Long id,
Map<String, Object> map)
I would like to use PathVariable such as the following:
#RequestMapping({"customer/{id}"})
public String surveys(HttpServletRequest request,
#PathVariable("id") Long id,
Map<String, Object> map)
How can I indicate whether a path variable is required or not? I need to make it optional because when creating a new object, there is no associated ID available until it is saved.
Thanks for help!
VTTom`s solution is right, just change "value" variable to array and list all url possibilities: value={"/", "/{id}"}
#RequestMapping(method=GET, value={"/", "/{id}"})
public void get(#PathVariable Optional<Integer> id) {
if (id.isPresent()) {
id.get() //returns the id
}
}
There's no way to make it optional, but you can create two methods with one having the #RequestMapping({"customer"}) annotation and the other having #RequestMapping({"customer/{id}"}) and then act accordingly in each.
I know this is an old question, but searching for "optional path variable" puts this answer high so i thought it would be worth pointing out that since Spring 4.1 using Java 1.8 this is possible using the java.util.Optional class.
an example would be (note the value must list all the potential routes that needs to match, ie. with the id path variable and without. Props to #martin-cmarko for pointing that out)
#RequestMapping(method=GET, value={"/", "/{id}"})
public void get(#PathVariable Optional<Integer> id) {
if (id.isPresent()) {
id.get() //returns the id
}
}
VTToms answer will not work as without id in path it will not be matched (i.e will not find corresponding HandlerMapping) and consequently controller will not be hit. Rather you can do -
#RequestMapping({"customer/{id}","customer"})
public String surveys(HttpServletRequest request, #PathVariable Map<String, String> pathVariablesMap, Map<String, Object> map) {
if (pathVariablesMap.containsKey("id")) {
//corresponds to path "customer/{id}"
}
else {
//corresponds to path "customer"
}
}
You can also use java.util.Optional which others have mentioned but it requires requires Spring 4.1+ and Java 1.8..
There is a problem with using 'Optional'(#PathVariable Optional id) or Map (#PathVariable Map pathVariables) in that if you then try to create a HATEOAS link by calling the controller method it will fail because Spring-hateoas seems to be pre java8 and has no support for 'Optional'. It also fails to call any method with #PathVariable Map annotation.
Here is an example that demonstrates the failure of Map
#RequestMapping(value={"/subs","/masterclient/{masterclient}/subs"}, method = RequestMethod.GET)
public List<Jobs> getJobListTest(
#PathVariable Map<String, String> pathVariables,
#RequestParam(value="count", required = false, defaultValue = defaultCount) int count)
{
if (pathVariables.containsKey("masterclient"))
{
System.out.println("Master Client = " + pathVariables.get("masterclient"));
}
else
{
System.out.println("No Master Client");
}
//Add a Link to the self here.
List list = new ArrayList<Jobs>();
list.add(linkTo(methodOn(ControllerJobs.class).getJobListTest(pathVariables, count)).withSelfRel());
return list;
}
I know this is an old question, but as none of the answers provide some updated information and as I was passing by this, I would like to add my contribution:
Since Spring MVC 4.3.3 introduced Web Improvements,
#PathVariable(required = false) //true is default value
is legal and possible.
#RequestMapping(path = {"/customer", "/customer/{id}"})
public String getCustomerById(#PathVariable("id") Optional<Long> id)
throws RecordNotFoundException
{
if(id.isPresent()) {
//get specific customer
} else {
//get all customer or any thing you want
}
}
Now all URLs are mapped and will work.
/customer/123
/customer/1000
/customer - WORKS NOW !!