I have a User entity. When I save a user document in the collection I'm hashing the password with #PrePersist but Morphia also calls #PrePersist when I try to update a document without password.
#PrePersist
void prePersist() {
if (password != null) {
System.out.println(password);
PasswordService service = new DefaultPasswordService();
password = service.encryptPassword(password);
}
}
This is my update operation.
#Override
public void updateWithoutPassword(T user) {
Query <T> query = userDAO.createQuery();
query.and(
query.criteria("_id").equal(user.getId())
);
UpdateOperations <T> updateOperations = userDAO.createUpdateOperations();
updateOperations.set("username", user.getUsername());
updateOperations.set("name", user.getName());
updateOperations.set("surname", user.getSurname());
updateOperations.set("department", user.getDepartment());
updateOperations.set("roles", user.getRoles());
userDAO.update(query, updateOperations);
}
When I call the updateWithoutPassword(), #PrePersist is running and password value is being the old password value and trying to hash the old password again. What am I doing wrong?
You should probably hash your password in setPassword() instead. #PrePersist will always run.
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?
One of my clients did not want to use any of the standard options (SMS or Email) for 2FA and I was wondering what others have implemented instead.
I felt that the site would be too vulnerable with just a username and password combination, even using max-attempts and timeouts.
A simple option that multiplies up the login uncertainty is by adding an additional security question as part of the login page.
My answer is posted below
Using the code-first approach in creating the user database, I added a set of security questions into my IdentityDbContext class.
public DbSet<SecurityQuestion> SecurityQuestions { get; set; }
This provides a simple list of questions such as "What is your favourite food". the questions should engender reasonably generic answers. The questions are added in the Configuration class Seed method
void AddSecurityQuestion(ApplicationDbContext db, string question)
{
db.SecurityQuestions.Add(new SecurityQuestion() { Question = question });
}
A simple table is sufficient
public class SecurityQuestion
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[StringLength(128)]
[DisplayName("Question")]
public string Question { get; set; }
}
A field as added to the Identity User class. This will contain either null or a hash of a security question and answer. For completeness, a property is added to check if the hash is present. The first time a user logs on, the hash is saved. On subsequent logons, the hash is checked
public string SecurityQuestion { get; protected set; }
[NotMapped]
public bool HasSecurityQuestion
{
get
{
return this.SecurityQuestion != null;
}
}
Hashing uses the same code as the internal Identity methods and stores the seed and hash in the same string
public static string HashSecurityQuestion(string question, string answer)
{
if (question == null)
{
throw new ArgumentNullException("Question is null");
}
if (answer == null)
{
throw new ArgumentNullException("Answer is null");
}
string questionAndAnswer = question + "_" + answer;
// random salt and hash in save result
byte[] salt;
byte[] buffer2;
using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(questionAndAnswer, 0x10, 0x3e8))
{
salt = bytes.Salt;
buffer2 = bytes.GetBytes(0x20);
}
byte[] dst = new byte[0x31];
Buffer.BlockCopy(salt, 0, dst, 1, 0x10);
Buffer.BlockCopy(buffer2, 0, dst, 0x11, 0x20);
return Convert.ToBase64String(dst);
}
A verification method is required
public static bool VerifyHashedPassword(string hashedSecurityQuestion, string question, string answer)
{
if (hashedSecurityQuestion == null)
{
return false;
}
if (question == null)
{
throw new ArgumentNullException("Question is null");
}
if (answer == null)
{
throw new ArgumentNullException("Answer is null");
}
string questionAndAnswer = question + "_" + answer;
// has to retrieve salt
byte[] buffer4;
byte[] src = Convert.FromBase64String(hashedSecurityQuestion);
if ((src.Length != 0x31) || (src[0] != 0))
{
return false;
}
byte[] dst = new byte[0x10];
Buffer.BlockCopy(src, 1, dst, 0, 0x10);
byte[] buffer3 = new byte[0x20];
Buffer.BlockCopy(src, 0x11, buffer3, 0, 0x20);
using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(questionAndAnswer, dst, 0x3e8))
{
buffer4 = bytes.GetBytes(0x20);
}
return buffer3.SequenceEqual(buffer4);
}
In the login process, there is one extra step to verify the security question and answer are checked. The MVC View displays a drop down of questions and a textbox for an answer, both values for which are in the view model
var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: true);
// if the user login is a success, check if a security question exists
if (result == SignInStatus.Success && user.HasSecurityQuestion)
{
// security question exists, so check it
if (!user.VerifySecrityQuestion(model.SecurityQuestion, model.SecurityQuestionAnswer))
{
result = SignInStatus.Failure;
}
}
Authy/Twilio Developer Evangelist here. There are a couple other options for additional security that you have:
Enforce & encourage strong passwords
This includes things like minimum length, showing a password "strength" indicator, and including easy ways for people to use a password manager.
I compiled more details about recommendations for strong passwords:
https://github.com/robinske/betterpasswords
One Time Passwords in the form of TOTP
This is what you'd see with apps like Authy or Google Authenticator. TOTP (time-based one time passwords) is a standard, you can read about that here.
Authy has APIs to implement OTPs here.
Push Authentication
This is another form of 2FA that allows your user to "approve" or "deny" a login request in the form of a push notification. This is the most secure form of 2FA with a seamless user experience, you can read more about how Authy does that here.
Authy has APIs to implement push authentication here.
========
Note: security questions are a lot like additional passwords that can be more easily Googled, so I'd encourage your client to think about using a true second factor.
I am registering a Servlet in an OSGi bundle using the HttpService. I have created my own HttpContext class which handles the security - BasicAuthentication and check against ActiveDirectory.
Dictionary<String, String> params = new Hashtable<String, String>();
params.put("jersey.config.server.provider.classnames", SettingsService.class.getName());
HttpContext ctx = new HttpContext()
{
#Override
public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException
{
// validation against Active Directory here
return ADAuth.authenticate(request, response);
}
#Override
public URL getResource(String name)
{
return null;
}
#Override
public String getMimeType(String name)
{
return null;
}
};
httpService.registerServlet("/rest", new MyServlet(), params, ctx); //$NON-NLS-1$
httpService.registerResources("/web", "/web", null);
So far so good. I would now like to set roles for the logged-in used so that I can use the #RolesAllowed annotation. The roles will depend on Active Directory groups.
How do I set the roles? I have tried setting roles using
HttpSession session = request.getSession(true);
Subject subject = (Subject) session.getAttribute("javax.security.auth.subject");
if (subject == null) {
subject = new Subject();
subject.getPrincipals().add(new PlainRolePrincipal(groupName));
session.setAttribute("javax.security.auth.subject", subject);
}
but request.isUserInRole always returns false.
Update
When I step into request.isUserInRole I eventually get to this code:
if (_authentication instanceof Authentication.Deferred)
setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
if (_authentication instanceof Authentication.User)
return ((Authentication.User)_authentication).isUserInRole(_scope,role);
return false;
The _authentication value is null. When / where should this be set?
You only created a new Subject instance. This does not automatically update the one in the session.
Apart from that the problem in jaas is always that there is not standard for role principals. You chose to encode the Role as PlainRolePrincipal. I am not sure this is what request is checking for. You will have to look into that code to see how it determines if a principal is a role principal or not.
A typical case is that it checks for a certain class or interface name but I am not sure which in your case.
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 ;)