need some help or direction using Spring's security 3.1.x.
I am storing an encrypted password in MySql database. Which password is defined as a varchar(60) column.
The first time running the web app, I generated the password with the following code snippet:
String p = "12345";
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encodedPassword = passwordEncoder.encode(p);
I then took the String encodedPassword and pasted into the database column. I kept the code in my authentication-manager (snippet follows), and logged encodedPassword to the server log.
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="usersDAO">
<security:password-encoder ref="encoder" />
</security:authentication-provider>
</security:authentication-manager>
<bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
My problem is that authentication fails with exception: Bad credentials when BCryptPasswordEncoder.matches() runs. The stored password is not matching the generated hash from the form input. The same text password that was used in the initial hash generation was used.
Each time I re-run the login entering the same text, the logged encodedPassword is different. Debugging I can see where the entity is being returned from the database correctly, so I don't think that is an issue. The issue seems to me that I'm not doing/setting something correctly in order to generate the same hash each time the text
password is entered.
EDIT:
Adding usersDAO.
import org.springframework.security.core.userdetails.UserDetailsService;
public interface UsersDAO extends Dao<Users>, UserDetailsService
{
Users getByUsername(String username);
}
EDIT:
adding implementation.
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Repository("usersDAO")
public class UsersDAO_DB extends AbstractHibernateDao<Users> implements UsersDAO
{
final Logger log = LoggerFactory.getLogger(this.getClass());
#Override
public Users getByUsername(String username)
{
String p = "12345";
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encodedPassword = passwordEncoder.encode(p);
log.debug("HELLOZ ----> " + encodedPassword);
notNull(username, "username can't be null");
return (Users) getSession()
.getNamedQuery("users.byUsername")
.setParameter("username", username)
.uniqueResult();
}
#Override
#Transactional
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
notNull(username, "username can't be null");
Users users = getByUsername(username);
if (users == null) {
throw new UsernameNotFoundException("No user with username " + username);
}
return users;
}
#Override
public void create(Users t)
{
// TODO Auto-generated method stub
}
#Override
public void update(Users t)
{
// TODO Auto-generated method stub
}
#Override
public void delete(Users t)
{
// TODO Auto-generated method stub
}
}
Any ideas?
This was a newbie error here following a couple of different tutorials.
In the bean I had defined my security encoder as a:
org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
To generate a test cryptic password I used the following code:
String p = "12345";
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encodedPassword = passwordEncoder.encode(p);
log.debug("HELLOZ ----> " + encodedPassword);
which was mixing the org.springframework.security.crypto.password.PasswordEncoder and the org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder. See the above code defining passwordEncoder.
Once I changed it to:
String p = "12345";
BCryptPasswordEncoder pe= new BCryptPasswordEncoder();
String encPassword =pe.encode(p);
log.debug("HELLB ----> " + encPassword);
copied the output to my database and retested everything worked fine.
Each time I re-run the login entering the same text, the logged encodedPassword is different".
Where is that logging coming from? Spring Security won't log incoming passwords and if you are using BCrypt it shouldn't be re-encoding them from scratch anywhere.
It sounds like you may be re-encoding the submitted password yourself, possibly in your usersDAO which isn't shown.
If not, please post your complete configuration and the logging output you're talking about.
Related
I have a user service. The service has the ability to reset the password.
#Service
public final class UserService {
private final UserMapper userMapper;
#Autowired
public UserService(final UserMapper userMapper) {
this.userMapper = userMapper;
}
#Transactional
public String restorePassword(final String loginOrEmail) throws IllegalArgumentException {
User user = userMapper.findByUsername(loginOrEmail);
if (user == null) {
user = userMapper.findByEmail(loginOrEmail);
if (user == null) throw new IllegalArgumentException("User not found");
}
final String newPassword = PasswordGenerator.generate(2, 2, 2, 4);
returnPasswordAfterRestore(newPassword, user);
//Later, the password will salt and be encrypted before entering the database.
userMapper.setPassword(newPassword, user.getUserId());
return user.getEmail();
}
public void returnPasswordAfterRestore(final String password, final User user) {
System.out.println("------------------------Method run!------------------------");
}
I need to get the generated password and send it to the user. For this I use Spring AOP.
#Before("execution(* com.example.aop.service.UserService.returnPasswordAfterRestore(..))&&args(password, user)")
public void beforeReturnPasswordAfterRestore(String password, User user) {
System.out.println("-------------------------------" + password);
System.out.println("-------------------------------" + user.getUsername() + " mail:" + user.getEmail());
}
When I make an explicit call to the returnPasswordAfterRestore () method, the aspect fulfills correctly and intercepts the parameters, this confirms the debug mode.
userService.returnPasswordAfterRestore("newPass", user);
But when I make a call to the restorePassword () method, which contains a call to the returnPasswordAfterRestore () method, the aspect does not work.
userService.restorePassword(user.getUsername());
How do I solve this problem? Or how can I get the generated password out of a method without saving it to an external variable?
I have an application where the login should include an organization number, so the login needs to be username + password + organization number.
Sample case: If the username + password matches with an existing user, I need to check if that user has the organization id. If not, the login should fail.
I saw that the login form from spring security plugin submits to /app/j_spring_security_check but couldn't find where that is actually implemented.
Also I'm not sure if touching that is the right way of implementing this custom login.
My question is where / how to customize the login action? (to make it fail on the case I described above).
We can do this by overriding the filter UserNamePasswordAuthenticationFilter and provide our custom attemptAuthentication.
So, go to DefaultSecurityConfig.groovy file (inside plugins). See tree diagram below:
target
|-work
|-plugins
|-spring-security-core-2.0-RC5
|-conf
|-DefaultSecurityConfig.groovy
In DefaultSecurityConfig.groovy under apf closure we specify filterProcessUrl which we can override in grails application's Config.groovy like we do for other properties (e.g. rejectIfNoRule)
grails.plugin.springsecurity.apf.filterProcessesUrl="your url"
Now we understood how it checks for authentication.Let's customise it own way by overriding the method attemptAuthentication of filter named UsernamePasswordAuthenticationFilter. For example, see below(also, go through the inline comments added there)
package org.springframework.security.web.authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.util.Assert;
public class CustomUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";
/** #deprecated */
#Deprecated
public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";
private String usernameParameter = "j_username";
private String passwordParameter = "j_password";
private String organisationParameter = 'j_organisation'
private boolean postOnly = true;
public UsernamePasswordAuthenticationFilter() {
super("/j_spring_security_check");
}
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if(this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
} else {
String username = this.obtainUsername(request);
String password = this.obtainPassword(request);
String password = this.obtainOrganisation(request);
//regular implementation in spring security plugin /**
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
this.setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
**/
//Your custom implementation goes here(Authenticate on the basis of organisation as well). Here you need to customise authenticate as per your requirement so that it checks for organisation as well.
}
protected String obtainOrganisation(HttpServletRequest request) {
return request.getParameter(this.organisationParameter);
}
protected String obtainPassword(HttpServletRequest request) {
return request.getParameter(this.passwordParameter);
}
protected String obtainUsername(HttpServletRequest request) {
return request.getParameter(this.usernameParameter);
}
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
public void setUsernameParameter(String usernameParameter) {
Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
this.usernameParameter = usernameParameter;
}
public void setPasswordParameter(String passwordParameter) {
Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
this.passwordParameter = passwordParameter;
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
public final String getUsernameParameter() {
return this.usernameParameter;
}
public final String getPasswordParameter() {
return this.passwordParameter;
}
}
Hence, it's more of a overriding task in terms of spring security.
To get more clearer idea about same read this nice link for java
and
for grails read this
Hope it helps.
These blogs gives a more detailed idea of the same requirements.
i wrote a normal html login form, that forwards to a vaadin project, where i want to receive the username and password and check if its valid. but i have problems getting this request.
when i add a requesthandler in the init() method of my UI class, i can only get the request data after the second call of the vaadin page (because at the first call of init, the hander ist not added yet)
#Override
protected void init(VaadinRequest vaadinRequest) {
setContent(new MainComponent());
VaadinSession.getCurrent().addRequestHandler(
new RequestHandler() {
#Override
public boolean handleRequest(VaadinSession vaadinSession, VaadinRequest vaadinRequest, VaadinResponse vaadinResponse) throws IOException {
String username = vaadinRequest.getParameter("username");
return false;
}
});
so i tried to overwrite the VaadinServlet method doPost, but it does not get triggered. when i overwrite the methode service(HttpServletRequest request, HttpServletResponse response), this method is triggered a serval times for each request, so also not a good place to get just the userdata.
so whats the right way to solve this problem?
i dont't know if this is the best solution, but at least it works. maybe this helps someone.
here a short explanation what i do. i retrieve the posted username and password from the post values of my plain html login formular from another url and see if it is existing in the database. if it exists, it returns the result, otherwise the value ERROR.
i extended the VaadinServlet and overwrote the method service like this
#Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
super.service(request, response);
String username = request.getParameter("username");
if(username != null) { // called several times, only set when username is returned, otherwise the value remains "error"
String password = request.getParameter("password");
this.result = getResult(username, Encrypter.encryp(password));
}
}
and this is inside my class extended from UI
#Override
protected void init(VaadinRequest vaadinRequest) {
MyServlet myServlet = (MyServlet) VaadinServlet.getCurrent();
String result = myServlet.getResult();
if(result .equals(MyServlet.ERROR)){ // check if the result set in the servlet is valid, otherwise forward to the loginpage
goToLogin();
myServlet.resetResult();
return;
}
myServlet.resetResult();
...
}
To whom it may concern - obtaining request and response in Vaadin 8 (which might be also available in Vaadin 7):
VaadinServletRequest vsRequest = (VaadinServletRequest) VaadinService.getCurrentRequest ();
HttpServletRequest httpServletRequest = vsRequest.getHttpServletRequest ();
VaadinServletResponse vsResponse = (VaadinServletResponse) VaadinService.getCurrentResponse ();
HttpServletResponse httpServletResponse = vsResponse.getHttpServletResponse ();
You can read the request parameter directly through the VaadinRequest object that's passed into init():
#Override
protected void init(VaadinRequest vaadinRequest) {
setContent(new MainComponent());
String username = vaadinRequest.getParameter("username");
}
It work for me perfect:
User is my simple class with username, name etc.
setting logged user in session:
public void setLoggedUser(User loggedUser) {
this.loggedUser = loggedUser;
getUI().getSession().getSession().setAttribute("loggedUser", loggedUser);
}
reading user:
loggedUser = (User) getUI().getSession().getSession().getAttribute("loggedUser"); //return null if not logged in
I am working with Selenium RC.
I am giving the data manually to selenium.Like below
selenium.type("id=username","myName");
selenium.type("id=password","myPassword");
selenium.click("id=login");
But, my doubt is is there any way to get the data dynamically? Here I am giving my Name directly into selenium.type();
Is there any way to retrieve username and password from other place like textfile or excel file?
Any help?
Short answer - YES.
Longer answer - You need to program it. So it is not possible using Selenium IDE, but you can use Selenium Webdriver. I am doing this in Java, so I will post you little snippets of my code, how do i do it.
1) I have special Java Class to hold the user information:
public class EUAUser {
private String username;
private String password;
private boolean isUsed
public EUAUser(String uname, String pwd){
this.username = uname;
this.password = pwd;
isUsed = false;
}
public String getPassword(){
return password;
}
public String getUsername(){
return username;
}
public void lockUser(){
isUsed = true;
}
}
2) Then I have UserPool to hold all users. So far because I need only 5 different users, I do it by quick and dirty approach:
public class UserPool {
private List<EUAUser> userList = new ArrayList<EUAUser>();
public UserPool(){
userList.add(new EUAUser("firstUser","a"));
userList.add(new EUAUser("MyUsername", "a"));
userList.add(new EUAUser("TestUser", "a"));
userList.add(new EUAUser("TSTUser2", "a"));
}
public EUAUser getNextUser() throws RuntimeException {
for(EUAUser user: userList){
if (!user.isUsed()){
user.lockUser();
return user;
}
}
throw new RuntimeException("No free user found.");
}
3) In tests I have something like this
UserPool pool = new UserPool();
EUAUser user = pool.getNextUser();
selenium.type("id=username", user.getUserName());
selenium.type("id=password", user.getPassword());
selenium.click("id=login");
The above code does
Add all known users to the UserPool
Retreive one free user from the pool
logs him into the app under username and password
In my case its really quick and dirty approach, but you can have list of users in file and load them into the UserPool using fileReader or something. Just giving you idea how you can do this ;)
Can I use recaptcha with apache wicket 1.5.3? Is there some good example?
In terms of Google reCAPTCHA v2, you can just follow its instruction, which is straightforward.
First of all, go to Google reCAPTCHA, and register your application there. Then you can work on the client and server sides respectively as below:
On the client side (see ref)
First, paste the snippet below <script...></script> before the closing tag on your HTML template, for example:
<script src='https://www.google.com/recaptcha/api.js'></script>
</head>
Then paste the snippet below <div...></div> at the end of the where you want the reCAPTCHA widget to appear, for example:
<div class="g-recaptcha" data-sitekey="{your public site key given by Google reCAPTCHA}"></div>
</form>
That's all on the client side.
On the server side (see ref)
When a user submits the form, you need to get the user response token from the g-recaptcha-response POST parameter. Then use the token, together with the secret key given by Google reCAPTCHA, and optional with the user's IP address, and then POST a request to the Google reCAPTCHA API. You'll then get the response from Google reCAPTHA, indicating whether the form verification succeeds or fails.
Below is the sample code on the server side.
User summits a Wicket form (Wicket 6 in this example):
protected void onSubmit() {
HttpServletRequest httpServletRequest = (HttpServletRequest)getRequest().getContainerRequest();
boolean isValidRecaptcha = ReCaptchaV2.getInstance().verify(httpServletRequest);
if(!isValidRecaptcha){
verificationFailedFeedbackPanel.setVisible(true);
return;
}
// reCAPTCHA verification succeeded, carry on handling form submission
...
}
ReCaptchaV2.java (Just Java, web framework independent)
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
public class ReCaptchaV2 {
private final static Logger logger = Logger.getLogger(ReCaptchaV2.class);
private final static String VERIFICATION_URL = "https://www.google.com/recaptcha/api/siteverify";
private final static String SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
private static ReCaptchaV2 instance = new ReCaptchaV2();
private ReCaptchaV2() {}
public static ReCaptchaV2 getInstance() {
return instance;
}
private boolean verify(String recaptchaUserResponse, String remoteip) {
boolean ret = false;
if (recaptchaUserResponse == null) {
return ret;
}
RestTemplate rt = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
map.add("secret", SECRET);
map.add("response", recaptchaUserResponse);
if (remoteip != null) {
map.add("remoteip", remoteip);
}
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<MultiValueMap<String, String>>(map, headers);
ResponseEntity<String> res = null;
try {
res = rt.exchange(VERIFICATION_URL, HttpMethod.POST, httpEntity, String.class);
} catch (Exception e) {
logger.error("Exception: " + e.getMessage());
}
if (res == null || res.getBody() == null) {
return ret;
}
Response response = null;
try {
response = new ObjectMapper().readValue(res.getBody(), Response.class);
} catch (Exception e) {
logger.error("Exception: " + e.getMessage());
}
if (response != null && response.isSuccess()) {
ret = true;
}
logger.info("Verification result: " + ret);
return ret;
}
public boolean verify(HttpServletRequest httpServletRequest) {
boolean ret = false;
if (httpServletRequest == null) {
return ret;
}
String recaptchaUserResponse = httpServletRequest.getParameter("g-recaptcha-response");
String remoteAddr = httpServletRequest.getRemoteAddr();
return verify(recaptchaUserResponse, remoteAddr);
}
}
Response.java (Java POJO)
public class Response {
private String challenge_ts;
private String hostname;
private boolean success;
public Response() {}
public String getChallenge_ts() {
return challenge_ts;
}
public void setChallenge_ts(String challenge_ts) {
this.challenge_ts = challenge_ts;
}
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
#Override
public String toString() {
return "ClassPojo [challenge_ts = " + challenge_ts + ", hostname = " + hostname + ", success = " + success + "]";
}
}
Have you read this?
I have added the guide here in case page disappears.
Usage
We will create a panel called RecaptchaPanel. In order to use this component to your application all you'll have to do is this:
add(new RecaptchaPanel("recaptcha"));
and of course, add the component in your markup:
<div wicket:id="recaptcha"></div>
Implementation
Implementation is simple. All you have to do, is to follow several steps:
Add recaptcha dependency to your project
<dependency>
<groupid>net.tanesha.recaptcha4j</groupid>
<artifactid>recaptcha4j</artifactid>
<version>0.0.7</version>
</dependency>
This library hides the implementation details and expose an API for dealing with recaptcha service.
Create associated markup (RecaptchaPanel.html)
<wicket:panel><div wicket:id="captcha"></div></wicket:panel>
Create RecaptchaPanel.java
import net.tanesha.recaptcha.ReCaptcha;
import net.tanesha.recaptcha.ReCaptchaFactory;
import net.tanesha.recaptcha.ReCaptchaImpl;
import net.tanesha.recaptcha.ReCaptchaResponse;
/**
* Displays recaptcha widget. It is configured using a pair of public/private keys which can be registered at the
* following location:
*
* https://www.google.com/recaptcha/admin/create
* <br>
* More details about recaptcha API: http://code.google.com/apis/recaptcha/intro.html
*
* #author Alex Objelean
*/
#SuppressWarnings("serial")
public class RecaptchaPanel extends Panel {
private static final Logger LOG = LoggerFactory.getLogger(RecaptchaPanel.class);
#SpringBean
private ServiceProvider serviceProvider;
public RecaptchaPanel(final String id) {
super(id);
final ReCaptcha recaptcha = ReCaptchaFactory.newReCaptcha(serviceProvider.getSettings().getRecaptchaPublicKey(),
serviceProvider.getSettings().getRecaptchaPrivateKey(), false);
add(new FormComponent<void>("captcha") {
#Override
protected void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) {
replaceComponentTagBody(markupStream, openTag, recaptcha.createRecaptchaHtml(null, null));
}
#Override
public void validate() {
final WebRequest request = (WebRequest)RequestCycle.get().getRequest();
final String remoteAddr = request.getHttpServletRequest().getRemoteAddr();
final ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
reCaptcha.setPrivateKey(serviceProvider.getSettings().getRecaptchaPrivateKey());
final String challenge = request.getParameter("recaptcha_challenge_field");
final String uresponse = request.getParameter("recaptcha_response_field");
final ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(remoteAddr, challenge, uresponse);
if (!reCaptchaResponse.isValid()) {
LOG.debug("wrong captcha");
error("Invalid captcha!");
}
}
});
}
}
</void>
Things to notice:
ServiceProvider - is a spring bean containing reCaptcha configurations (public key and private key). These keys are different depending on the domain where your application is deployed (by default works for any key when using localhost domain). You can generate keys here: https://www.google.com/recaptcha/admin/create
The RecaptchaPanel contains a FormComponent, which allows implementing validate method, containing the validation logic.
Because reCaptcha use hardcoded values for hidden fields, this component cannot have multiple independent instances on the same page.
Maybe the xaloon wicket components can be a solution for you. They have a Recaptcha plugin.