WebDAV unlock foreign exclusive write lock - locking

I am implementing a webdav server and have one question regarding opaquelocktoken:
Is it correct that
everybody who knows the opaquelocktoken have write access, e.g. unlock or delete the resource?
propfind will show the opaquelocktoken to everybody?
I have tested the following scenario with the tomcat webdav implementation:
I) I lock a resource by netcat, lock owner is "netcat"
II) I retrieve the lock properties for the resource with DAVExplorer
III) I try to delete the resource with DAVExplorer
=> It works.
The DAVExplorer sent the following request.
DELETE without opaquelocktoken ==> 423 Locked
PROPFIND for lockdiscovery => opaquelocktoken was delivered
DELETE with opaquelocktoken => 204 No Content
One more information: I have no authentication active. Is this the reason why a client have write access to a resource that was locked by another client?

a) Locking is for coordinating (serializing) access; not for access control. See RFC 3744 for the WebDAV ACL spec. So yes, in absence of other access controls the lock token will be sufficient.
b) And no, PROPFIND doesn't need to reveal the lock token; whether it does or not is implementation-specific.

Related

Is there a way to handle password changes smoothly in a CALDAV scenario without locking accounts?

i have a scenario running with an own CALDAV-server and CALDAV-clients like (iOS-calendar, mac-Calendar, Android sync adapter, Thunderbird/Lightning, Outlook Sync, ...)
The authentication so far works via basic auth (https and the "Authentication"-Header).
The CALDAV-clients store the user/password in their configuration.
So far so good, but the issue comes now once the password of the user/account either gets changed, reset, expired, etc.
The server has a restrictive password policy enforced, which locks the account after x failed attempts (e.g. 10).
What is happening now obviously is, that once the CALDAV-client configuration was not updated it continues to use an old password.
The server responds with an 401 not authorized - ok, thats fine apparently again.
But the Clients still continue to use the outdated password. It would be nicer to stop polling and present the user with a dialog that his credentials are not valid anymore. But the clients are out of my control so nothing can be directly done here.
The result: after 2-3 iterations (as most clients tries multiple request in one sync iteration) the account on the server of the user is locked due to too many failed login attempts.
That is not nice. The issue seems to be generic and known as "stale passwords".
A solution could only be a better client handling (out of scope here) or a oAuth-token handling. But i was not able to find anything that standard CALDAV-clients supports this. Only google calendar seems to enforce an oAuth2 authorization before allowing CALDAV communication.
So the question is, is there a good way to improve the bad experience of locked accounts?
Some special 401 response which tells the clients to forget the password or not using it again?
constructive feedback highly welcome.
Edit:
for macOS and ios calendar i found a strange behavior (bug) causing and/or enforcing the described situation.
A standard 401 response will cause the clients to bring up the password dialog as expected and described above. The clients stop polling until a new password is entered - as desired.
In my case the 401 response body contained an inline base 64 image (img src="data..."):
This doesnt lead to a password renewal dialog! Just a "something goes wrong" error state.
The clients are continuing to poll! Locking the accounts after some tries ;(
A solution for this problem than will be to remove the inline image but for me it sounds like a bug that an inline image in the 401 response provokes a different behavior on the client.
Some special 401 response which tells the clients to forget the password or not using it again?
Well, 401 is that response. If the client receives a 401 it knows the the login/password combination it provided doesn't work anymore, and shouldn't retry with the same. Obviously the clients don't do this, partially because:
On the other side your servers x-failed-attempts locking doesn't work with stateless protocols for obvious reasons. HTTP doesn't have that feature builtin. Locking the account is a side effect a client doesn't have to expect when running idempotent HTTP requests.
Assume the client is downloading 10 batches of items concurrently. If the credentials invalidate during this, the account would immediately be locked :-)
Summary: You can't use basic auth naively with backends that lock accounts after n-tries.
Google and iCloud both use token based auth schemes (Google OAuth, iCloud a proprietary one). You can't expect those to work in other clients. E.g. while the Apple clients support OAuth for Google, I don't think they support that for other account types.
So what can you do
I'm reading your question so that you own the account server and that the account locking is intentional and desired. (I.e. it is not a side effect of a different (e.g. SSO) backend system you reach out to.)
I think in this case it should be reasonable to rework your account system to allow unlimited login attempts with just the old password.
The lock-after-n-attempts measure is to protect against people trying different passwords. In your case it is always the same and as a bonus it also matches the old password.
There are a lot of different variations of this approach.

Shibboleth Session Unauthorized

My experience with Shibboleth is limited and I have no access to configuration or logs on the IdP or the SP. I am trying to troubleshoot this issue:
Previous Shibboleth session is still active on the client workstation. When attempting to access document protected by the following .htaccess configuration:
AuthType shibboleth
ShibRequestSetting requireSession 1
require valid-user
The client (occasionally) receives the following error message:
Authorization Failed
Based on the information provided to this application about you, you are not authorized to access the resource at "http://myresourcepath"
Please contact the administrator of this service or application if you believe this to be an error
In troubleshooting, I changed .htaccess from
require valid-user
to:
require shib-session
I thought the issue might be the deprecated parameter- but after changing, I was still receiving the authorization failed message. The only way to successfully authorize is to clear the browser cache, revisit the page which then it prompts for authentication, and then authorization passes its check and you hit the page successfully with no error.
What complicates matters even more, is, when .htaccess is set to:
require shib-session
The authorization error message persists even after clearing the cache and re-authenticating. I had to change .htaccess back to
require valid-user
I dont know what could cause the random authorization issue, if the session wasn't valid, the user would get directed to the idp for login, correct? Thats Shibboleth's design. So, the session has to be valid- but why does it not recognize the user as authorized for that resource?
Additionally:
after I received the message and googled quickly, it seems like a stock response from the idp:
https://technical.bestgrid.org/index.php/Vladimir's_general_Shiboleth_notes
says:
This specific example asks for the user variable to be set to any value - and any Shibboleth attribute can be used with the variable name it is assigned to in the Attribute Acceptance policy (AAP.xml). For more syntax on using the require directive, see the examples in the SP htaccess documentation on specific features implemented for the Apache require directive.
Users who do not have the attribute (or do not provide it), get the following error message (with the Shibboleth logo). .... is same message....
This form of control however may not be that user friendly - user would have to know to go either use Autograph to allow the release of the attribute, or talk to their IdP administrator to configure the attributes on the IdP.
Also note that this does not work with lazy sessions - in which case one immediately gets the same error message.
Further, note that care must be taken with overlapping access control blocks. These should be listed from the most-generic ("/") to the most specific (as "/secure" in the above example). Otherwise, the more relaxed settings on the generic one would override the more stringent settings on the specific one.

LDAP "force-change-on-add" can't be handled properly

I'm using openDJ LDAP server for authentication process of a Java based project using JNDI.
Most of the other things like password expired, invalid credentials can be handled using exceptions. (using the understandable message in exception, or using the error codes in some occasions)
ds-cfg-force-change-on-add and ds-cfg-force-change-on-reset attributes are set to true in the password policy.
But when a newly created user logs in or, when a user logs in after a password reset by admin no exceptions occur.
Can somebody tell me how to handle this.
One alternative in this case is the password policy request and response controls (example) defined in draft-behera-ldap-password-policy, supported by OpenDJ LDAP SDK and other SDKs. You pass the request control to the directory server, and you get back a response control.
The response control indicates whether the password needs to be changed, why a requested password modification could not complete, how much time remains before expiration, etc.

CAS authentication and limiting access for specified users

I'm using CAS (Central Authentication Service) from Jasig in a client JSF app running on tomcat 6 server. I would like to limit the access to the app just for the users specified in my database rather than all the users which can be authenticated using that CAS service. When the user attempts to log in, I need to check if his username is also in my database's table user and if it is - allow the access to the app. Otherwise, I would like to redirect user to a page "You don't have permission to access this part of the application". So I need authorization as well. Is there a good way to authorize the users in jsf 2.0? Thanks in advance for any help/suggestions.
Sounds like you need to design a custom Authentication Handler class in CAS. In theory, your handler would extend this [1], perform all the necessary checks and database look ups and will then be able to return a signal that indicates whether or not the user could authN.
You should then reference your custom handler in the deploerConfigContext.xml file.
For displaying the message, you could either throw an exception with the proper messages code, such that the message would appear above the login form, or you could alter the spring webflow and generate a new view-state which the user would be redirected to, if they fail to get access. The first approach is much easier to implement.
Another approach would be to take advantage of the isUserInRole() method [2] using the persondir api.
[1] http://developer.jasig.org/projects/cas/cas-server-core/cas-server/cas-server-core/apidocs/org/jasig/cas/authentication/handler/support/AbstractUsernamePasswordAuthenticationHandler.html
[2] https://wiki.jasig.org/pages/viewpage.action?pageId=47874068

How to use LDAP credentials offline?

I would like to use an LDAP server (probably Apache directory) to manage logins and credentials for an application. From time to time the application needs to work offline (on a laptop) without a connection to the LDAP server.
What is the best way to replicate the credentials localy?
I have already thought about:
Using Mitosis to replicate the LDAP server on the laptop.
But it would be a quite "heavy" and complicated solution. Moreover Mitosis seems not be be finished yet.
Exporting the credentials as LDIF file that could be stored on the laptop.
But I would need a way to check that the LDIF file actually comes from the LDAP server (The file should include a kind of signature). Moreover I would like to reject LDIF files that haven't be updated for more than a week. It would be nice if I could avoid implementing signing and age check myself.
Any other ideas or tools that could help me?
Edited Edit: I had a look at Kerberos because the documentation of the Java-Kerberos-API seems to say that it is possible to use a cached ticket in a local cache and I thought this might be a solution for me. Moreover Kerberos can be added as plugin to Apache Directory.
But the Kerberos cache stores decrypted tickets (aiming at sharing them with other applications). I would need the crypted version of the ticket to be able to check the user password during an offline session. Conclusion: Kerberos doesn't offer a simple solution to my problem.
Knowing that it will be probably ok if the user have to log on once online before being able to log on offline, consider the following algorithm:
user provides your application with a (username + password)
application attempts to contact LDAP for authentication
working online? (e.g. connection successful)
application authenticates against LDAP using (username + password)
authentication succesful?
application stores or updates hash(password) as (cached_credentials) for (username) into local secure storage
application proceeds as authenticated [[STOP]]
authentication failed?
application proceeds as non-authenticated (incorrect credentials) [[STOP]]
working offline? (e.g. network error)
application attempts retrieve (cached_credentials) for (username) from local secure storage
(cached_credentials) exists AND more recent than (1 week)?
application compares (cached_credentials) against hash(password)
match?
application proceeds as authenticated [[STOP]]
no match?
application proceeds as non-authenticated (incorrect credentials) [[STOP]]
(cached_credentials) does not exist OR less recent than (1 week)?
application proceeds as non-authenticated (network error) [[STOP]]
This is (or was, IIRC), by the way, the same model employed by Windows NT+ for user authentication against domain controllers. Upon login an attempt is made to authenticate against the domain controller and create or update the local (cached) version of the user profile. If the domain controller is not available, the user is prompted to proceed with authentication against the credentials captured in the local (cached) profile (if one exists.)
EDIT
Yes, this is, in spirit, the same solution as copying an ldif file locally, except that you do not have to parse ldif when you're offline. :)
It is understood that you can store any additional attributes (permissions, etc.) in your cache
It is also understood that 'secure storage' is at least signed. :) You can do this easily enough with a SHA-1 hash and a secret, or you can use full-fledged cryptographic providers available on your platform (or in Java, if using Java.) You do not need to crypt it as long as no secret information is stored inside.
Here is the solution I decided to use (I have already described it in an edit to my question, but I would like to able to accept an answer to "close" the question):
As I have not found another solution, I decided to use an LDIF export, add a timestamp as comment at the beginning of the file and then sign the file. To sign the file I calculate an hash value (SHA-1) of the file + a secret key. The signature is added as comment at the beginning of the file. To check the signature I remove the first line of the signed file and recalculate the hash value.