WCF Authentication -- Authenticate user/pass one time, then authenticate some other way afterwards? - wcf

Basically, I have the following scenario and information:
We're using HTTPS.
We want to authenticate a user by user/pass when they first log in.
After they are authenticated, I want any future calls to OTHER services (not the login service) to use the username and some sort of session (in case the password changes in the middle of a session).
I want to make sure my sessions can timeout and control them in a way that if a user tries to call a service and they don't have a session they get an error (cause they haven't logged in). Not sure if there's a WCF built-in way to do sessions this way or if I'll have to do something customized with a database.
I think we want to use WSHttpBinding (not BasicHttpBinding), 90% sure on this.
I just can't seem to figure out how to do this. Often time's I'll find information on the client code doing client.ClientCredentials.UserName.UserName = username and client.ClientCredentials.UserName.Password = password. But, that just doesn't work because what is my server checking against? I'm trying to grab that info and validate it against a database of user/passes. I'm not looking to use Windows Authentication or that sort (because I don't care who is logged into the computer, just who is logging into the app).

You want to use a Secure Token Service (STS) to authenticate and get a Security Token (maybe SAML) back that identifies the user which can then be passed to your other services and they can just use the identity information to identify and authorize because they trust the STS has verified the user's identity up front.
This is a large subject to discuss, so I suggest searching for WCF STS and doing some more research, but that's definitely the direction I'd recommend going. If you're going to build your own STS implementation, I also recommend looking into using the Windows Identity Foundation (WIF) components to ease your development efforts.
Here's the download link for WIF v1.0 which is the latest version at the time of this answer.

Related

How to maintain connectivity to Office365 with Mailkit without reauthenticating user each email sent

Some background information which could be helpful to other potential solutions. My organization uses my windows login to also access other software applications such as office365 (outlook online and outlook desktop app). This password is required to be updated every so often and all other applications update together all at once so they are all interconnected. I am assuming there is some identity server or something which is tying it all together for authentication. So I am building a ASP.NET Core application which a user logs in via different username and password that is stored in a SQL Server. My web application will soon require email functionality so the users can send emails after doing some function in the application. Therefore I have put together the following code from examples online which does in fact work and let me send emails through our office365 email accounts using our organization official username(assigned email address for the mailkit below) and passwords.
public void SendEmail()
{
// create email message
var email = new MimeMessage();
email.From.Add(MailboxAddress.Parse("myEmail#something.org"));
email.To.Add(MailboxAddress.Parse("recipient#something.org"));
email.Subject = "my Subject";
email.Body = new TextPart(TextFormat.Plain) { Text = "Email sending has been integrated!" };
//send email
using var smtp = new SmtpClient();
//office 365
//Office 365 does not support NTML (windows authentication) so we need some sort of interation with an API to not store usernames and passwords.
smtp.Connect("smtp.office365.com", 587, SecureSocketOptions.StartTls);
smtp.Authenticate("myEmail#something.org", "passwordDuh");
smtp.Send(email);
smtp.Disconnect(true);
}
Since my web application does not connect to this identity server for authentication (really do not have much information on this internal service for my organization and my web application is more of a side project for my team) I have to manually insert the username and password into the code above. For testing purposes I have just added them in but I need to automate this or improve the code to be up to best practices. Therefore, I have thought of the following solutions but I am not sure of the feasibility of some of them or if there is a better/more appropriate solution:
Forgo my current username and password setup in the SQL DB and authenticate users at login with this identity server indirectly by using the current line below for mailkit and use in my login class to check the credentials against office365 (which probably uses our organizations identity server since the passwords are all linked with it):
smtp.Authenticate("myEmail#something.org", "passwordDuh")
And if it succeeds to authenticate then I know the office365 credentials are correct and I will create my authentication token as usual that I send for the users frontend to log into the site and stay logged in. My issue with this is I am not sure how I could stay connected to office365 so that I could send emails later on in the application use. It is unclear if this connection and authentication technique expires after some time if the user hasnt sent an email for an hour or so.
Use a similar approach to 1 but if I cannot keep the connection open I can take the user password if authenticated with office365 and encrypt the password with a salt then store in session a session variable. From everything I have read on stack answers seem to advice against storing passwords in plaintext in session and say to encrypt it but the responses tend to also give the sense this is still not adviced to keep even an encrypted password in session.
Figure out some way to get a token from office365 when a user logs into my site and authenticates with office365. Reading some solutions regarding getting an access token from office365 seems to indicate you need to have the application registered in azure and approved by an admin. This seems more like an api token to access their api for my application itself and not using a users username and password. I am less familiar with this solution so forgive me for my ignorance but I have tried researching this quite a bit and seems to not lead me to anything I can use unless I am missing something.
My organization uses my windows login to also access other software applications such as office365 (outlook online and outlook desktop app).
Oof. That's not a good practice.
Forgo my current username and password setup in the SQL DB and authenticate users at login with this identity server indirectly by using the current line below for mailkit and use in my login class to check the credentials against office365 (which probably uses our organizations identity server since the passwords are all linked with it):
I'm not sure I understand how this would work. Are you saying that when a user connects to your web service, they would have to provide their login credentials that you would then send to office365 to test to see if authentication is successful?
>_<
That seems like a hack that I doubt security experts would approve of since it requires passing along naked passwords.
A better approach (although I am no security expert, so take this with a grain of salt) might be to use an OAuth2 code flow to authenticate with office365 which would give you an access token that could then be used later for sending mails via MailKit's SmtpClient.
My issue with this is I am not sure how I could stay connected to office365 so that I could send emails later on in the application use. It is unclear if this connection and authentication technique expires after some time if the user hasnt sent an email for an hour or so.
You'd have to spawn a thread or something that would periodically call SmtpClient's NoOp() method (or NoOpAsync()). to keep the connection alive, although even this could eventually fail to keep that connection open eventually, so you'd have to be able to deal with a situation where the connection gets dropped.
Use a similar approach to 1 but if I cannot keep the connection open I can take the user password if authenticated with office365 and encrypt the password with a salt then store in session a session variable. From everything I have read on stack answers seem to advice against storing passwords in plaintext in session and say to encrypt it but the responses tend to also give the sense this is still not adviced to keep even an encrypted password in session.
Yea, not a great approach. You'd obviously still have to have a way to decrypt the password again and therein lies the weakness.
Figure out some way to get a token from office365 when a user logs into my site and authenticates with office365. Reading some solutions regarding getting an access token from office365 seems to indicate you need to have the application registered in azure and approved by an admin. This seems more like an api token to access their api for my application itself and not using a users username and password. I am less familiar with this solution so forgive me for my ignorance but I have tried researching this quite a bit and seems to not lead me to anything I can use unless I am missing something.
They are talking about an OAuth2 access token and this is most likely the correct way to go.
I wrote up some documentation on how to do this with a native desktop app, but I never got around to documenting this for an ASP.NET (or ASP.NET Core) web app. You can find the docs for the desktop app here: https://github.com/jstedfast/MailKit/blob/master/ExchangeOAuth2.md
Someone recently submitted ASP.NET web app docs for similar GMail authentication which can be found here: https://github.com/jstedfast/MailKit/blob/master/GMailOAuth2.md#authenticating-an-aspnet-web-app-with-the-oauth2-client-id-and-secret
You'll likely need to read the docs and find some samples for ASP.NET Core usage, but it's possible to do.

Securely using JSON web tokens to programmatically authenticate a user from one system into another

My team and I have been working on a web application for our clients that uses JSON web tokens for authentication and authorization. Using Azure AD as our identity provider, we verify a user's identity and generate a signed JWT with the user's permissions in it. The JWT then gets included in the authorization header of all subsequent requests to the APIs. Pretty standard stuff as far as JWTs go.
We're now being asked to provide the capability to link directly into our system from another third-party web application without forcing the user to reauthenticate. I'm trying to figure out if there's a way to do so without creating a massive security loophole.
The way I picture this working would be to implement an endpoint for programmatic authentication in our system that accepts a cryptographically signed payload with an API key and the user's ID or email address. The third-party system would have a private key with which to sign the payload, and we'd have a public one to verify the signature. If the request is legitimate, we'd issue a token for the specified user, and they could use that to link to whatever they like.
I'm already getting yelled at by at least one person that this is a complete joke from a security standpoint because, among other things, it completely bypasses AAD authentication. I believe the third-party system in question does use AAD for authentication, but that's not really relevant either way because we're trusting them implicitly whether they've authenticated their users or not. Either way I take his point.
I'm not a security expert and I don't claim to know whether there even is a proper way to do this kind of thing, but from my vantage it doesn't really seem all that much less secure than any other mechanism of authentication and authorization using JWTs. Is that true? Are we nuts for even trying? Is there a way to do it that's more secure? What should I know about this that I demonstrably don't already?
Thanks in advance for the help. At the very least I hope this spurs some helpful conversation.
Single Sign-On (SSO) enables users to enter their credentials once to sign in and establish a session which can be reused across multiple applications without requiring to authenticate again. This provides a seamless experience to the user and reduces the repeated prompts for credentials.
Azure AD provides SSO capabilities to applications by setting a session cookie when the user authenticates the first time. The MSAL.js library allows applications to leverage this in a few ways.
MSAL relies on the session cookie to provide SSO for the user between different applications.
Read more in this documentation.

What is the difference between the two use cases of using OpenID Connect in Keycloak? (Client vs Application)

I am very new to the concepts of SSO and Keycloak. I am trying to read the official documentation of Keycloak. In the "Supported Protocols" part (https://www.keycloak.org/docs/latest/securing_apps/index.html), the documentation talks about the two use cases of using OIDC like this:
"The first is an application that asks the Keycloak server to authenticate a user for them. After a successful login, the application will receive an identity token and an access token. The identity token contains information about the user such as username, email, and other profile information. The access token is digitally signed by the realm and contains access information (like user role mappings) that the application can use to determine what resources the user is allowed to access on the application.
The second type of use cases is that of a client that wants to gain access to remote services. In this case, the client asks Keycloak to obtain an access token it can use to invoke on other remote services on behalf of the user. Keycloak authenticates the user then asks the user for consent to grant access to the client requesting it. The client then receives the access token. This access token is digitally signed by the realm. The client can make REST invocations on remote services using this access token. The REST service extracts the access token, verifies the signature of the token, then decides based on access information within the token whether or not to process the request."
What I do not understand is this: In the first paragraph it talks about an application making a request and in the second one it talks about a client. But aren't applications counted as clients? Why the specific differentiation? And can anyone given an example of the remote services that is talked about in the second part?
Thank you.
But aren't applications counted as clients? Why the specific differentiation? And can anyone given an example of the remote services that is talked about in the second part?
Yes exactly it. The reason for the differentiation is because there could be many applications more than just this one client. And the client, that the user is authed against may want to access all those other applications' data.
For example take the google ecosystem. Does google email have access to drive, and photos, etc... While it could out the box, it doesn't. You need to explicitly allow email "offline access" to those other applications, even though they are all part of the same platform.
Keycloak understands this and provides that terminology. But it is a bit confusing because this isn't the best way to think about it. Instead a better explanation is that there is just the user and service clients. The service clients all talk to each other and ask for a user's data. While a user may want their data by going straight to one application, other applications may want that user's data too.
Assuming you want to actually allow one service to ask for user data from another service, you want to be using something that supports authorization as a service and not just authentication. There are some examples of this, such as PolicyServer and Authress.

Best way to protect a REST service that will be accessed by mobile and desktop applications

I have REST services that I was planning on protecting with Windows Integrated Authentication (NTLM), as it should only be accessible to those internal to the company, and it will end up being on a website that is accessible by the public.
But, then I thought about mobile applications and I realized that Android, for example, won't be able to pass the credentials needed, so now I am stuck on how to protect it.
This is written in WCF 4.0, and my thought was to get the credentials, then determine who the user is and then check if they can use the GET request and see the data.
I don't want to force the user to pass passwords, as this will then be in the IIS log, and so is a security hole.
My present concern is for the GET request, as POST will be handled by the same method I expect.
One solution, which I don't think is a good option, would be to have them log into Sharepoint, then accept only forwarded reqests from Sharepoint.
Another approach would be to put my SSO solution in front of these services, which would then force people to log in if they don't have credentials, so the authentication would be done by SSO, and since the web service directory could be a subdirectory of the main SSO page, then I could decrypt the cookie and get the username that way, but, that would be annoying for the mobile users, which would include the senior management.
So, what is a way to secure a REST service so that it is known whom is making the request so that authorization decisions can be made, and will work for iphones, android and blackberry smartphones.
I have the same problem so let me give you the details and would also appreciate feedback. Since you are using an internal system you have one extra option that I have listed.
My first option isn't perfect, yes it could be hacked but still - better than nothing. With each request you pass the device's unique identifier along with a hash. You generate the hash using a salt embedded in the application along with the id. On the server you match the incoming hash with one you generate at the server, with the passed unique identifier. If someone "roots" their device, and is smart enough they could find the salt - you can obscure it further but ultimately it could be stolen. Also, I keep all requests on SSL to just help hide the process. My "enhancement" to this process is to pass back new salts after each request. New devices get 1 chance to obtain the next salt or get locked out ... not sure about that step yet.
Now another approach, is to have the user enter a "salt" or username and password only an internal user would know - the device obtains a token and then passes it (on SSL) with each request. Nobody outside your company could obtain that so this is probably best. I can't use this since my app is in the app store.
Hope that helps! Let us all know if you ever found a good solution.
My current solution, in order to protect data in the system, is to force people to first log in to the application that the REST services support (our learning management system), as I have written an SSO solution that will write out a cookie with encrypted data.
Then, the REST service will look for that cookie, which disappears when you close the browser, and I don't care if the cookie is expired, I just need the username from it, then I can look in a config file to see if that user is allowed to use that REST service.
This isn't ideal, and what I want to do is redirect through the SSO code, and have it then send the person back to the REST service, but that is not as simple as I hoped.
My SSO code has lots of redirects, and will redirect someone to a spot they pick in the learning management system, I just need to get it to work with the other application.

Best way for a remote web app to authenticate users in my current web app?

So a bit of background, I'm working on an existing web application which has a set of users, who are able to log in via a traditional login screen with a user name and password, etc.
Recently we've managed to score a client (who have their own Intranet site), who are wanting to be able to have their users log into their Intranet site, and then have their users click a link on their Intranet which redirects to our application and logs them into it automatically.
I've had two suggestions on how to implement this so far:
Create a URL which takes 2 parameters (which are "username" and "password") and have the Intranet site pass those parameters to us (our connection is via SSL/TLS so it's all encrypted). This would work fine, but it seems a little "hacky", and also means that the logins and passwords have to be the same on both systems (and having to write some kind of web service which can update the passwords for users - which also seems a bit insecure)
Provide a token to the Intranet, so when the client clicks on a link on the Intranet, it sends the token to us, along with the user name (and no password) which means they're authenticated. Again, this sounds a bit hacky as isn't that essentially the same as providing everyone with the same password to log in?
So to summarise, I'm after the following things:
A way for the users who are already authenticated on the Intranet to log into our system without too much messing around, and without using an external system to authenticate, i.e. LDAP / Kerberos
Something which isn't too specific to this client, and can easily be implemented by other Intranets to log in
Both of your suggested options are insecure, even if you use SSL. Never pass credentials on a URL, put them in the HTTP request by using POST.
There is a standard called SAML and this can be used to solve your problem. The challenge is choosing which version to implement. I would choose SAML 2.0.
Google Apps implements a flavor of SAML 2.0 and allow you to authenticate using your intranet credentials. In the case of your application, you would be the service provider and your client would be the identity provider. As long as you implement the standard correctly you should be able to support any new client (identity provider). Here is a list of SAML implementations you might want to take a look at. If you need the client to pass over information in addition to the authentication information then SAML can facilitate this with metadata.
You will still need to implement SSL to encrypt network traffic.
I hate to answer my own question, but I hate even more a question with no answer. In the end we went with a very similar implementation of SalesForce's delegated authentication SSO implementation.
http://wiki.developerforce.com/page/How_to_Implement_Single_Sign-On_with_Force.com
Essentially the solution has a trusted site, known as the delegated authentication authority, who has a list of users who are logged into the company intranet.
When the user logs into the company intranet, and they click a link to our application, the company intranet will pass the user name and a generated token (which expires after a set amount of time) to our application.
Our application will then check if the user name is on our site, and if so, send the username / token (along with the source IP and a few other parameters) to the delegated authentication authority. If all those items match on the delegated authentication authority, it returns true and the user can log in. If it returns false the user is denied access.
We've found this system to work quite well, and even implemented a couple of extra security features like SSL, client side certificates, VPN tunnel, and even restricting the IP addresses which can access the site and the delegated authentication authority.
I know it's bad form to answer your own question but I hope this helps someone else who might be having the same problem ...