Hi,
I think that your approach is correct in case that method
identityManager.validateCredentials(creds);
returns Status.INVALID in case that invalid credentials are provided and
valid credentials are expired.
I am looking at credentials a bit and checked that it's not the case
actually at least for PasswordCredentialHandler, which returns
Status.EXPIRED before it validates the provided password. So if saved
password is expired, it doesn't matter if you provide valid or invalid
password for validation as it returns Status.EXPIRED in both cases.
See testcase, which is currently passing for me:
@Test
@Configuration(exclude = LDAPStoreConfigurationTester.class)
public void testExpirationWithInvalidPassword() throws Exception {
IdentityManager identityManager = getIdentityManager();
User user = createUser("someUser");
Password plainTextPassword = new
Password("some_password".toCharArray());
Calendar expirationDate = Calendar.getInstance();
expirationDate.add(Calendar.MINUTE, -5);
identityManager.updateCredential(user, plainTextPassword, new
Date(), expirationDate.getTime());
UsernamePasswordCredentials credential = new
UsernamePasswordCredentials();
credential.setUsername(user.getLoginName());
credential.setPassword(new Password("invalidPassword"));
// Trigger validation with invalid password
identityManager.validateCredentials(credential);
// Password status is not INVALID but EXPIRED
assertEquals(Status.EXPIRED, credential.getStatus());
}
So in your case, I am thinking about this scenario:
- john sets his password
- This password will expire after 7 days
- Then attacker will try to reset john's password. Now he can do it even
if parameter "currentPassword" contains invalid password because the
condition:
if (EXPIRED.equals(creds.getStatus()) ||
VALID.equals(creds.getStatus()))
will be met.
I am not sure if this could be classified as bug in Picketlink, but IMO
it could be (ie. we should return Status.INVALID with bigger priority
than Status.EXPIRED). What are others thinking?
Marek
On 6.8.2013 15:42, Bruno Oliveira wrote:
> Thanks guys for the clarification. Let's suppose I don't have any sorta
> of default users into my system, only a registered user john with
> password 123 and the following scenarios:
>> 1. John's password has expired and must be changed
> 2. John is paranoid and wants to reset his password every week.
>> The approach bellow is correct? Bear in mind that with the status
> EXPIRED the method "isLoggedIn" will return false.
>> @PUT
> @Path("/reset")
> public Response reset(final String username, final String
> currentPassword,
> final String newPassword) {
>> Credentials creds = new UsernamePasswordCredentials(username,
> new Password(currentPassword));
>> identityManager.validateCredentials(creds);
>> if (EXPIRED.equals(creds.getStatus()) ||
> VALID.equals(creds.getStatus())) {
>> User user = identityManager.getUser(username);
> identityManager.updateCredential(user, new
> Password(newPassword));
>> return Response.ok().build();
>> }
>> return Response.status(Status.FORBIDDEN).build();
> }
>> I agree that user should never provide the previous password to change
> it, only a check if the user is logged and authorized should be enough.
> But once isLoggedIn will return false for EXPIRED credentials what is
> the correct approach?
>> Does the snippet above make sense?
>> Pedro Igor Silva wrote:
>> +1
>>>> ----- Original Message -----
>> From: "Bill Burke" <bburke at redhat.com>
>> To: security-dev at lists.jboss.org>> Sent: Monday, August 5, 2013 6:45:18 PM
>> Subject: Re: [security-dev] Reseting passwords
>>>> IMO, the IDM API is a low-level API. What you're suggesting should be
>> handled by the subsystem invoking the IDM API.
>>>> BTW, beta6 has drastically changed the API, so you might want to update :)
>>>> On 8/5/2013 5:09 PM, Bruno Oliveira wrote:
>>> Good morning, on AeroGear we have the following scenario with PicketLink
>>> beta5:
>>>>>> - Default user "admin" which must change her password at first
>>> deployment, otherwise she will not be able to login
>>>>>> During the startup we have the following piece of code:
>>>>>> @Singleton
>>> @Startup
>>> public class PicketLinkDefaultUsers {
>>>>>> @Inject
>>> private IdentityManager identityManager;
>>>>>> @PostConstruct
>>> public void create() {
>>>>>> User adminUser = identityManager.getUser("admin");
>>>>>> Developer admin = new Developer();
>>> admin.setLoginName("admin");
>>>>>> this.identityManager.add(admin);
>>> this.identityManager.updateCredential(admin, new
>>> Password("123"), new Date(), expirationDate());
>>>>>> Role roleDeveloper = new SimpleRole("admin");
>>> this.identityManager.add(roleDeveloper);
>>> identityManager.grantRole(admin, roleDeveloper);
>>>>>> }
>>>>>> //Expiration date of the password
>>> private Date expirationDate() {
>>> Calendar expirationDate = Calendar.getInstance();
>>> expirationDate.add(Calendar.HOUR, -1);
>>> return expirationDate.getTime();
>>> }
>>> }
>>>>>> On login:
>>>>>> public boolean login(User user, String password) {
>>>>>> credentials.setUserId(user.getLoginName());
>>> credentials.setCredential(new Password(password));
>>>>>> if (identity.login() != Identity.AuthenticationResult.SUCCESS) {
>>> return false;
>>> }
>>>>>> return true;
>>> }
>>>>>> Now to reset the password:
>>>>>> this.identityManager.updateCredential(admin, new Password(newPassword));
>>>>>> And here comes my question. At least to me it looks like is possible to
>>> change admin's password by just guessing the username, my concern is
>>> about an attacker being able to escalate privileges (I can be wrong). On
>>> PicketLink do we have something internally like password matching? Or
>>> maybe some mechanism to force user to change their password upon first
>>> login? For example (just a very stupid example):
>>>>>> this.identityManager.updateCredential(admin, oldPassword, newPassword);
>>>>>> The correct solution (I guess) would be to check if that user has
>>> already logged in and force admin to supply the new password, but the
>>> method isLoggedIn will return false for credentials with status EXPIRED.
>>>>>> An alternative with the current scenario (maybe is just the lack of
>>> knowledge in API usability) would be to validate and check credential
>>> status.
>>>>>> Credentials credential = new UsernamePasswordCredentials("username", new
>>> Password(password));
>>> identityManager.validateCredentials(credential);
>>>>>> But I think that might exist something on PicketLink to verify if the
>>> session exists, before reset user's password.
>>>>>> Any ideas?
>>>>>> -- abstractj
>>> _______________________________________________
>>> security-dev mailing list
>>>security-dev at lists.jboss.org>>>https://lists.jboss.org/mailman/listinfo/security-dev>>>