I I have been searching a lot for answer to this question. However after reading a lot of resources including Spring Security documentation as well I am still away from completely
understanding as to how to authenticate a user for REST API using Spring Security .
Here is what I want to do:
1) I want to implement authentication like Amazon S3 service using public-private key
2) For that I will be sending an HMAC token with every request and public key in authorization header or my own custom header.
3) I want to use spring security to achieve server side handling of the token as follows:
1) fetch the public key from the header.
2) get the private key stored in database using my cutsom UserDetailService class
3) calculate the HMAC token on server side using request and private key just like I do it on client
4) compare two tokens to verify user
5) if successful,store authentication object in SecurityContextHolder.
From above I am not sure how to do this in Spring Security. What I have understood is as follows:
1) Use a <http> element along with custom filter. I have done this as follows
<http use-expressions="true" create-session="stateless"
authentication-manager-ref="restAuthenticationManager"
entry-point-ref="jkwebRestAuthenticationEntryPoint">
<intercept-url pattern="/api/**" access="isAuthenticated()">
</intercept-url>
<custom-filter ref="jkWebSecurityHmacAuthenticationFilter"
position="FORM_LOGIN_FILTER"/>
</http>
2) Now I can get access the header in this filter and access public key from it.
However, I am not sure how to retrieve the private key from database using this public key. Do I need to use custom AuthenticationManager or AuthenticationProvider? and how to do this.OR can I directly inject my UserDetailService Bean into filter bean as it is?
3) If I do not need to use custom AuthenticationManager or AuthenticationProvider and I can inject UserDetailService directly into filter bean,then do I need custom AuthenticationEntryPoint?
4) Assuming I am able to retrieve and do authentication in the filter do I need to just call chain.doFilter and request will be forwarded to the appropriate controller?
5) in case if authentication fails in the filter how I should 401 resonse to client or custom authentication entry point need to be used? if yes how?
6) also I need to put Authioities in UserDetails which I construct in UserDetailsService implementation and set it in UserDetails object. Just by setting the authentication object in security context will do the job and authorization will be carried our once authentication is successful?
I can post more code for clarity if needed.
Related
There are some restful apis, as follows:
api/v1/billing/invoices/{invoiceNumber}
api/v1/billing/transactions/{transactionNumber}
And, each invoice or transaction belong to a specific account.
When implementing the restful apis, we must meet: Each account can only view their own invoice or transaction.
How should we isolate the data in restful apis?
Of course, we can pass the account number to the api, such as:
api/v1//billing/invoices/{invoiceNumber}?accoutNumber=XXX
api/v1/billing/{accountNumber}/invoices/{invoiceNumber}
But the Invoice Number has been able to uniquely identify a resource. So I do not want the problem to be complicated.
Is there any other way to solve this problem?
You are mixing a lot of things here.
This is not a REST problem, this is a security problem. More precisely, it's a OWASP top 10 2013 Insecure direct object vulnerability.
Let's make it simple: you have a URL like this
.../superSensitiveStuff/1
and you want to prevent the owner of "1" from accessing to ".../superSensitiveStuff/2"
To the best of my knowledge, there are three ways of dealing with this issue:
enforcing integrity in request URLs. This strategy does not apply to all cases, it only works in those scenarios where the client issues a request to a resource previously communicated by the server. In this case, the server may add a query param like this
.../superSensitiveStuff/1?sec=HMAC(.../superSensitiveStuff/1)
where HMAC is a cryptographic HASH function. If the parameter is missing, the server will drop the request and if it's there the server will be able to verify that it's exactly the authorized URL because the HMAC value guarantees its integrity(for additional infos, hit the link above).
using unpredictable references. The problem here is that a user can guess another id. "uhmm... I have the resource number 1, let me check whether the resource number 2 exists". If you drop sequences and move to long random number this is very hard to do. The resource will become
.../superSensitiveStuff/195A23FR3548...32OT465
This is good because it's effective and cheap.
exploiting a mixed RBAC-ABAC approach. RBAC stands for Role Based Access Control and this is what you are using. The leading A of the second acronym stands for Attribute. This means that access is provided on the basis of a user role and an attribute. In this case is the userId, since it must be authenticated for accessing private resources. In few words, when a user requests a specific .../superSensitiveStuff resource it is loaded from the repository when you have the ownership information for that resource. It could be a DB, for example, and your SuperSensitiveStuff java business model could be like this
public class SuperSensitiveStuff {
private String userId;
private String secretStuff;
...
}
now, in your controller you can do the following
String principal = getPrincipal(); //you request the logged userId
SuperSensitiveStuff resource = myService.load(id); //you load the resource using the {id} in the request path
if (resource.getUserId.equals(principal))
return resource //200 ok, this is an authorized access
else
throw new EvilAttemptException() //401 unauthorized, cheater detected
JOSE4J takes the jwks_uri as its starting point for JWT validation and I wondered whether it would be possible to support the Discovery Document as the starting point and JOSE4J would pick up the jwks_uri from there and then go the the JWKS key document to pick the public key matching the JWT at had through the kid. This way I only have to hardcode the discovery document uri in my code, as I worry a bit whether the jwks_uri might change without notice, the wellknow discovery document is to my knowledge fixed.
This is how it works now:
// The HttpsJwksVerificationKeyResolver uses JWKs obtained from the HttpsJwks and will select the
// most appropriate one to use for verification based on the Key ID and other factors provided
// in the header of the JWS/JWT.
HttpsJwksVerificationKeyResolver httpsJwksKeyResolver =
new HttpsJwksVerificationKeyResolver(https_jwks);
Maybe it would be nice to have the resolver recognize whether the discovery document uri is passed in or not and behave accordingly.
Thanks!
Jan
There's no direct support for it but you could implement your own VerificationKeyResolver with that logic (would likely use HttpsJwksVerificationKeyResolver internally). Or the application code could (periodically) pull the jwks_uri value from discovery document and use it to create the HttpsJwksVerificationKeyResolver.
I need to authenticate a SAML Respone , The Identity Provider has provided a metadata file. What are the steps to verify the SAML Response against contents of metadata ?.
One common answer, based around most federated SAML systems, is that you need to use the public key from the metadata to verify the signed response. If verifying a signature with a public key is an unfamiliar concept, spend a little time reading around PKI or "public key infrastructure." Then you should move to the XML Signature Specification.
I note that CAS uses SAML2 but does not build its trust infrastructure on signatures but on whitelists of service providers who are allowed to present tokens.
If you are using the PKI trust model, the signature should be in the <ds:Signature> element. The metadata should contain the public key in the <KeyDescriptor> element, ideally with the attribute use = signing. See Section "5 SAML and XML Signature Syntax and Processing" of the SAML Core specification for more details.
Other security checks include:
Is there a "InResponseTo" attribute? From Core: "...it MUST be present and its value MUST match the value of the corresponding request's ID
attribute."
Is there a "Destination" attribute? From Core: "If it is present, the actual recipient MUST check that the URI reference identifies the location at which the message was received. If it does not, the response MUST be discarded. "
I'm using the parse REST API.
I need to setup so that for any requests made:
1) only logged in/authenticated users can Read or Write.
2) users can only access/modify records they own.
My current implementation:
1) using the Application key + REST API key.
2) sending request to user login endpoint, on success returning the user data including the session token
for 2), I'm not doing anything with the session token yet.
I understand that parse has:
1) class based permissions
2) object-level permissions (ACL's)
With Read and Write access on the class level, and by simply using the Application Key + REST API Keys,
anyone with these two keys can access that class (ofcourse, the Master Key has even more "power").
I want to simply say that they can Read and Write on the class level, if they're logged in/authenticated.
And when they Read, Update or Delete, they can only do so if they're owner of the object.
I assume that session token will play a role in the logged in part, and ownership is defined by object-level ACL
Is this correct and how to roughly set this scenario up in parse?
It's not clear to me in the REST API how to handle this (what I think is a common) type of scenario.
Thanks for any feedback
{"ACL":{"$CURRENT_USER":{"read":true,"write":true}}}
above in acl column will mean at the security level, only the creator has RW permissions. No other user can see these records with this ACL attr value regardless of their access on the CLASS level.
OR
you control the accessor predicates in your app. So you can add a column = 'createdBY' of type pointer_to_class_User.
Any queries just contain predicate ..
'where={"createdBy":{"__type":"Pointer","className":"User","objectId":"$CURRENT_USER"}}'
which enforces ( outside row security level ) idea of only getting result sets containing rows for the current-user.
all depends on how you want to use the security layer.
I would do it using the predicates and resort to the ACL only where you may have stuff like SSN's or Salary where as a policy you dont what general read permissions.
I am developing a REST API layer for my application using Zend_Rest_Controller. I have an authenticate method where the clients will pass the apikey and after the key is authorized I have to create a session (for which I'm using new Zend_Session_Namespace(<32 bit unique session key which I'm generating>)) which need to be retrieved in subsequent API calls where the client will pass the same session key which I generated in the previous step.
It looks like Zend uses PHPSESSID variable to retrieve the session object and since my clients use, curl there is no guarantee that the same request object will be used in subsequent calls.
In a nutshell - I want to generate a 32 bit unique string and then use that as a key to store the session object and then use that key to restore my session object in the next call. And in the process I don't want Zend to use the PHPSESSID variable.
Any help will be greatly appreciated!
Cheers
The Zend_Session API documentation lists a setId method:
setId() - set an id to a user specified id
throws: Zend_Session_Exception
access: public static void setId (string $id)
string $id