Retrieving email address from Yesod OpenID - haskell

Is there any way to retrieve a user's email address after authenticating with Yesod's OpenId implementation?
In my test app, the redirection and authentication occur correctly, and maybeAuthId gives me an id to the corresponding entry in my database. However, that identity is stored as a URL.
I can work with this, but it'd be nice to also get the actual email used to authenticate as other OpenId packages allow. Is this possible with Yesod's OpenId? Is there something I can do with authOpenIdExtended (unclear how to use it)?

Have a look at the GoogleEmail module. One thing you need to keep in mind is that you can't necessarily trust every OpenID provider out there. If you use the email address for anything important, a nefarious user could simply set up an OpenID provider that let's him/her claim whichever address he/she wishes.

After looking into this again, I found an answer:
First, we need to use authOpenIdExtended with the right parameters:
authPlugins _ = [authOpenIdExtended [("openid.ns.ax", "http://openid.net/srv/ax/1.0"),
("openid.ax.mode", "fetch_request"),
("openid.ax.type.email", "http://axschema.org/contact/email"),
("openid.ax.required", "email")
]]
I found these values from this page: https://developers.google.com/accounts/docs/OpenID and verified them to work with Google and Yahoo.
Then, to use our retrieved email address, we call "credsExtra creds" on the creds parameter passed to getAuthId. This gives us a list of tuples containing the response from the OpenId provider. When using the parameters above to authOpenIdExtended we find our email in the key/value tuples with the values "openid.ax.value.email" (for Yahoo) or "openid.ext1.value.email" (for Google). I was expecting Google to also use the "openid.ax.value.email" key, but close enough.
I hope this helps someone.

Related

How can I protect a express route without authentication?

I'm trying to implement a GET method with Express in my nodeJs application.
I'd like to do something like this in order to display user data :
router.get("/user/:idUser", (req, res) => {
The user doesn't need to be authenticated in order to execute this code. However I don't want that anybody can execute this request with a user id of someone else. Because he could see data he's not supposed to see.
How could I proceed ? I thought about using some encryption process to have something like :
/user/PdfgdfJFDGTfrfgdsf
Your question isn't really making sense. You don't want authentication, but you only want a user to be able to view their own data so nobody else can view it.
The ONLY way to solve that is by using some form of authentication. The user has to prove to the server that they are allowed to view that data before the user renders the page for them.
Yes, you could obscure the URL (make it some mostly unguessable string of characters), but it's not clear what problem that is solving. The user themselves won't be able to remember it or type it so it would probably have to be a link in a web page and if it's a link in an unauthenticated web page, then anyone can get to it - thus defeating the purpose.
There are cases where temporary links (often done for privileged downloads) such as what you mention /user/PdfgdfJFDGTfrfgdsf are sent via an authenticated channel (either an authenticated webpage or sent to an email address known to belong to an authenticated user) and these links contain some unique and hard to guess code. The user can then click on that link (in authenticated webpage or in email) and access that resource without further authentication. In that case, the knowledge of the code in the URL is serving as a form of proof of authentication. Because URLs may be logged in service providers or corporate infrastructure and thus not remain entirely private, this technique has its limitations and is typically only used for short term (download this resource in the next 10 minutes) type of uses, not a long term substitute for authentication and not used for things that demand real security. You don't explain enough of your use case to know whether this is practical for your situation or not.
The user doesn't need to be authenticated in order to execute this code. However I don't want that anybody can execute this request with a user id of someone else. Because he could see data he's not supposed to see.
That's an inconsistent statement. You say "user doesn't need to be authenticated in order to execute this code" and then you say "I don't want that anybody can execute this request with a user id of someone else.". You can't have both. The user is either required to prove authorization or they aren't. Pick one. It can't be both.
you can use jwt for this and a auth middleware for this
upon decoding jwt token, you can implement logic to check if the decodedToken.user_id (given that you add user_id when encode token payload) is equal to the :idUser in route (or any kind of logic you want) there.

Practical examples of authorizing a RESTful service?

There are many excellent questions (and answers) on S.O. around the subject of REST and security. Many say "purists won't like this, but blah blah"... and then others says "you should never do that, because blah blah".
But I have not seen the solution that the "purists" are suggesting for the following scenario. So my question is - what are the "pure RESTful solutions" to the following scenario?
The simple scenario...
Imagine building a database/website that lets a user manage their favorite recipes. The website exposes a RESTful API so that users can query and manipulate their list from a custom program that they want to write (that utilizes this API).
So, user "A" has 3 favorite recipes with the ID's "1", "2" and "3".
User "B" has 2 favorite recipes with the ID's "4" and "5".
We need to make sure that if user A sends a DELETE command to /Recipes/4 that he will get a Forbidden (403) response.
What I would normally do...
What I would normally do is make them first call an authentication method, and send them some sort of auth-token that is valid for 30 minutes or so. Typically this token would be passed via a cookie.
What is the pure solution?
Is the pure REST solution to have them pass it as a variable in the query string? Are cookies the devil? Should the token be used as a segment of the URL (as opposed to a query string parameter)? Is there something else that answers this question clearly?
Pass the token in the authorization header. That's what it is designed for. See http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p7-auth-12.html
Treat the auth token as a resource.
You authenticate by GETting an auth token with parameters being credentials (basic auth over https for example).
Logout by DELETE'ing the auth token resource you got when logging in.
A simple stateless and cookie free solution would be giving each of your users an identical token.
There are ways to generate those tokens so that they are sparse enough for security concerns.
e.g. https://www.grc.com/passwords.htm
Suppose you have user A and user B. You generate a token X for user A and a token Y for user B.
So the user A will use something like /X/Recipes/1
and user B will use something like /Y/Recipes/4
It's safe because user A is the only one knows his token and as I mentioned before, the way you generate tokens can make sure it's "impossible" for others to guess that token.
So if someone else, like user B uses some other token in the url, say /Z/Recipes/1, you should be able to recognize and return a corresponding error message.
You can let user deliver the token in url, like I showed above, or embed it in HTTP request as Autherticantion message.

Secure OpenID user authentication

My goal is a secure login in system such as stackoverflow uses. I am a newbie but as you have probably seen I have spent all day looking up stackoverflow articles on security. As a result of this research I have now worked out a plan of attack. In particular this page was a great help Using OpenID for website Authentication. Can you please tell me if the following system would be a secure system and if not how should I improve the system.
Use OpenID to validate users.
Once a user has been validated by OpenID get user's email address from OpenID.
Hash the email address and store in session variable.
Compare Hashed email address to list of hashed email addresses in databases
Return content appropriate to that user based on the hashed email address.
In particular I am nervous about using the email address instead of the ProviderOpenID.
Please assume that I have (as I have found answers to these questions on other stackoverflow pages):
Properly destroyed sessions after use.
Setup my server to store session data in an inaccessible location.
Setup my database in a secure manner.
I am using SSL to ensure traffic cannot be intercepted.
Thanks in advance.
In general, your way better of using some authentication architecture for the language you are using that supports OpenID. Not only is it more secure, its just easier, you write less code, and you don't have to maintain that code or test it. There are ones for PHP,python,c#/asp.net, rails. A lot of frameworks also have support.
First, why not use the provided ID ?
I think you have two problems:
Its possible that an openID provider could return a email address for a different domain than the provider's.
For example, gmail could authenticate me correctly but I could specify that my email address was billg#microsoft.com. Then you would read my identity as me being Bill Gates despite the fact that it is not. There are of course ways to prevent this, but the standard system probably has safeguards included and even if it doesn't, it is someone else's responsibility to fix them and other people will be looking at those issues.
If I am reading the wikipedia article correctly, openID id's are not necessarily email addresses
This is not a security problem , but it does break expected behavior.

Security concerns regarding username / password vs secret URL

I have a simple site with a sign-up form. Currently the user can complement their registration with (non-critical, "low security") information not available at the time of the sign-up, through a personal (secret) URL.
I.e., once they click submit, they get a message like:
Thanks for signing up. You can complement your registration by adding information through this personal URL:
http://www.example.com/extra_info/cwm8iue2gi
Now, my client asks me to extend the application to allow users to change their registration completely, including more sensitive information such as billing address etc.
My question: Are there any security issues with having a secret URL instead of a full username / password system?
The only concern I can come up with is that URLs are stored in the browser history. This doesn't worry me much though. Am I missing something?
It's not the end of the world if someone changes some other users registration info. (It would just involve some extra manual labor.) I will not go through the extent of setting up https for this application.
This approach is not appropriate for sensitive information because it's part of the HTTP request URL, which is not encrypted and shows up in many places such as proxy and other server logs. Even using HTTPS, you can't encrypt this part of the payload, so it's not an appropriate way to pass the token.
BTW, another problem with this scheme is if you send the URL to the user via email. That opens up several more avenues for attack.
A better scheme would require some small secret that is not in the email. But it can be challenging to decide what that secret should be. Usually the answer is: password.
Another potential problem lies with the users themselves. Most folks realize that a password is something they should try to protect. However, how many users are likely to recognize that they ought to be making some sort of effort to protect your secret URL?
The problem here is that although it is hard to guess the URL for any specific user, given enough users it becomes relatively easy to guess a correct url for SOME user.
This would be a classic example of a birthday attack.
ETA: Missed the part about the size of the secret, so this doesn't really apply in your case, but will leave the answer here since it might apply in the more general case.
can complement their registration with (non-critical, "low security") information
It's hard to imagine what user-supplied information really is "low-security"; even if you are asking for a password and a username from your customers you are potenitally violating a duty of care to your customers; a large propertion of users will use the same username/password on multiple sites. Any information about your users and potentially a lot of information about transactions can be used by a third party to compromise the identity of that user.
Any information about the user should be supplied in an enctypted format (e.g. via https). And you should take appropriate measures to protect the data you store (e.g. hashing passwords).
Your idea of using a secret URL, means that only you, the user, anyone on the same network as the user, in the vicinity of a user on wifi, connected to any network between you and the user, or whom has access to the users hardware will know the URL. Of course that's not considering the possibility of someone trying a brute force attack against the URLs.
C.
The secret URL means nothing if you're not using SSL. If you're still having the end-user transmit their identifying information across the Internet in the clear, then it doesn't matter how you're letting them in: They are still exposed.
The "secret URL" is often referred to as security by obscurity. The issue is that it is super simple to write a script that will attempt various combinations of letters, symbols, and numbers to brute force hack this scheme.
So if any sensitive information is stored you should definitely use at least a username and password to secure it.

What are best practices for activation/registration/password-reset links in emails with nonce

Applications send out emails to verify user accounts or reset a password. I believe the following is the way it should be and I am asking for references and implementations.
If an application has to send out a link in an email to verify the user's address, according to my view, the link and the application's processing of the link should have the following characteristics:
The link contains a nonce in the request URI (http://host/path?nonce).
On following the link (GET), the user is presented a form, optionally with the nonce.
User confirms the input (POST).
The server receives the request and
checks input parameters,
performs the change,
and invalidates the nonce.
This should be correct per HTTP RFC on Safe and Idempotent Methods.
The problem is that this process involves one additional page or user action (item 3), which is considered superfluous (if not useless) by a lot of people. I had problems presenting this approach to peers and customers, so I am asking for input on this from a broader technical group. The only argument I had against skipping the POST step was a possible pre-loading of the link from the browser.
Are there references on this subject that might better explain the idea and convince even a non-technical person (best practices from journals, blogs, ...)?
Are there reference sites (preferably popular and with many users) that implement this approach?
If not, are there documented reasons or equivalent alternatives?
Thank you,
Kariem
Details spared
I have kept the main part short, but to reduce too much discussion around the details which I had intentionally left out, I will add a few assumptions:
The content of the email is not part of this discussion. The user knows that she has to click the link to perform the action. If the user does not react, nothing will happen, which is also known.
We do not have to indicate why we are mailing the user, nor the communication policy. We assume that the user expects to receive the email.
The nonce has an expiration timestamp and is directly associated with the recipients email address to reduce duplicates.
Notes
With OpenID and the like, normal web applications are relieved from implementing standard user account management (password, email ...), but still some customers want 'their own users'
Strangely enough I haven't found a satisfying question nor answer here yet. What I have found so far:
Answer by Don in HTTP POST with URL query parameters — good idea or not?
Question from Thomas -- When do you use POST and when do you use GET?
This question is very similar to Implementing secure, unique “single-use” activation URLs in ASP.NET (C#).
My answer there is close to your scheme, with a few issues pointed out - such as short period of validity, handling double signups, etc.
Your use of a cryptographic nonce is also important, that many tend to skip over - e.g. "lets just use a GUID"...
One new point that you do raise, and this is important here, is wrt the idempotency of GET.
Whilst I agree with your general intent, its clear that idempotency is in direct contradiction to one-time links, which is a necessity in some situations such as this.
I would have liked to posit that this doesn't really violate the idempotentness of the GET, but unfortunately it does... On the other hand, the RFC says GET SHOULD be idempotent, its not a MUST. So I would say forgo it in this case, and stick to the one-time auto-invalidated links.
If you really want to aim for strict RFC compliance, and not get into non-idempotent(?) GETs, you can have the GET page auto-submit the POST - kind of a loophole around that bit of the RFC, but legit, and you dont require the user to double-optin, and you're not bugging him...
You dont really have to worry about preloading (are you talkng about CSRF, or browser-optimizers?)... CSRF is useless because of the nonce, and optimizers usually wont process javascript (used to auto-submit) on the preloaded page.
About password reset:
The practice of doing this by sending an email to the user's registered email address is, while very common in practice, not good security. Doing this fully outsources your application security to the user's email provider. It does not matter how long passwords you require and whatever clever password hashing you use. I will be able to get into your site by reading the email sent out to the user, given that I have access to the email account or am able to read the unencrypted email anywhere on its way to the user (think: evil sysadmins).
This might or might not be important depending on the security requirements of the site in question, but I, as a user of the site, would at least want to be able to disable such a password reset function since I consider it unsafe.
I found this white paper that discusses the topic.
The short version of how to do it in a secure way:
Require hard facts about the account
username.
email address.
10 digit account number or other information
like social security number.
Require that the user answers at least three predefined questions (predefined by you,
don't let the user create his own questions) that can not be trivial. Like "What's
your favorite vacation spot", not "What's your favorite color".
Optionally: Send a confirmation code to a predefined email address or cell number (SMS) that the user has to input.
Allow the user to input a new password.
I generally agree with you with some modification suggested below.
User registers at your site providing an email.
Verification email is sent to the users account with two links:
a) One link with the GUID to verify the registration b) One link with the GUID to reject the verification
When they visit the verification url from their email they are automatically verified and the verification guid is marked as such in your system.
When they visit the rejection url from their email they are automatically removed from the queue of possible verifications but more importantly you can tell the user that you are sorry for the email registration and give them further options such as removing their email from your system. This will stop any custom service type complaints about someone entering my email in your system...blah blah blah.
Yes, you should assume that when they click the verification link that they are verified. Making them click a second button in a page is a bit much and only needed for double opt in style registration where you plan to spam the person that registered. Standard registration/verification schemes don't usually require this.

Resources