asp.net Web Api custom authentication requirement for mobile client - restful-authentication

Please provide your feedback on my solution against following requirements.
Requirement (similar to):
1.a let say that authentication Token is made out of the Email and date and is encrypted
1.b authentication Token is send back to the client through header
1.c authentication Token is stored on client and server
My solution :
1) To send authentication Token back to the client through header. i have used cookie, and following code.
HttpCookie cookie = new HttpCookie("AuthenticationToken");
cookie.Value = "EncryptedToken";
Response.Cookies.Add(cookie);
2) I will store authentication Token in database, and for each request i compare token saved in cookie with token stored in database. (assume that encrypt,decrypt operations are done properly )
Your feedback/commments?

It looks to me OK. However, if you are encrypting (so you can decrypt back) and can find out email (identifying user) and time token issued (hence verify whether expired or not), do you still need to store it in database? I would, only if i had other requirements such tracking, etc.

I have no expert knowledge in security. To me your idea sounds doable.
However, I was curious why you wanted to do "custom" authentication like this?
Have you taken a look at "build it" ASP.NET authentication done in Web.API?
Then you could create a custom HttpOperationHandler using standard .net stuff like:
var ticket = FormsAuthentication.Decrypt(val);
var ident = new FormsIdentity(ticket);
...
var principle = new GenericPrincipal(identity, new string[0]);
Thread.CurrentPrincipal = principle;
...
if (!principal.Identity.IsAuthenticated)
return false;
Also, you might want to read about Thread.CurrentPrincipal and Current.User
The pro is that you don't need to store authentication token in some DB on the server and retrieve it on every request.

Related

Adding claims to already logged in user with Bearer token authentication

I have a .Net 6 application. I would like to persist some data to the user session and thought claims is probably an easy way to do it.
As far as I can understand this is the correct way to add claims to the user after the initial login.
var claims = new List<Claim>
{
new Claim("claimType", "blabla")
};
context.User.AddIdentity(new ClaimsIdentity(claims));
If I check the Identities before that request ends there is a new record added which contains the claim I created. But upon the next request to the server it is gone. Only the original Identity is there again.
The value I want to add is calculated during runtime and can't be created during login. I could add it to the database but I REALLY don't want to as I need to check it on every request.
What might I be doing wrong? Or any suggestions to alternate ways to store the information?
Update 1:
Because it might matter, we use an external identity provider and token based authentication to a .net 6 api.

Oauth with same credentials and multiple sessions

I am working on an eCommerce Website and an App. We use SAP Hybris for OAuth 2.0.
To get an access token I send a Cliend ID, Client secret, Username and Password to the auth server.
Problem Example:
If I log in with the App first and then the Website, I won't be able to refresh my token in one of the sessions.
The token I receive from the server is pretty standard and looks like this:
{
"access_token":"9T7IziRSIM_QIqFtttM8rhf83zU",
"token_type":"bearer",
"refresh_token":"MztkOmh67gIEiMwX5sED-Rug51c",
"expires_in":43199,
"scope":"basic"
}
The only difference is that in the "Website Token" the expires_in would have a lower value than 43199 since it was requested after the "App Token".
Since both the access_token as well as the refresh_token are identical, the moment one of them expire and we try to fetch a new token the first session that does it will receive completely different credentials. As soon as the second session (which is now expired) tries to also refresh it's credentials the server will deny new credentials since the old credentials can be used only once to get new tokens.
Every 12 hours the tokens become expired and the first client to request a new token effectively logs out the other client by doing so.
Question:
What could I do to deal with this problem?
I was thinking it should be possible to send a unique ID to my request to generate a unique token. However I cannot find any information about this on the SAP Docs.

ServiceStack cookie value not same session id in Redis cache

I have configured AuthFeature with CustomUserSession and use RedisCache as User Auth Repository. And then I use C# JSON service client to authenticate service, authen OK but session ID store in cache does not same as cookie value.
Cookie: ss-id => I0ZIuzLijch3IY9Tut0z
Cache: urn:iauthsession:brSXBQPjmIB6Srv6EPCv
Please help !
Update ...
Below code use JsonServiceClient: using (var client = new JsonServiceClient("https://api.futabus.vn/api"))
{
var lRes = client.Post("/auth/credentials", new
{
UserName = user.UserName,
Password = user.Password
});
}
BUT when i post direct to https://api.futabus.vn/api/auth/credentials then cookie value same as session id in response object and in cache.
This contains nowhere near enough info to identify the issue, you should at a minimum show the HTTP Headers and code used to make the request.
But the session key is derived from the sessionId if it's not using ss-id then you're likely authenticating with RememberMe=true in which case ServiceStack stores the User Session against the ss-pid Cookie instead. If it's not then double-check the HTTP Headers as the Cookie you think is being sent is likely not the one being sent.
I have 3 applications:
1. Main website: example.com
2. User website: id.example.com
3. API: api.example.com. All cookies restrict to the first (1) website (root domain)
All websites have been written with ServiceStack Framework 4.0.
When i call Authentication from the second (2) to api.example.com using JsonServiceClient then:
the cookies store in the first (1) and cookies i get as soon as call authentication are different.
I think cookies store in the first (1) have been encrypted.
The first (1) using Form Authentication with machine key settings in web.config
Anyone else have idea?

LinkedIn JS API token exchange to REST token using Spring Social for Linkedin

I'm trying to do the following:
Let the user authenticate and authorize through Linkedin using Linkedin JSAPI, then take the authentication details and send them to my server to get the user profile via server side communication.
I got the Linkedin button setup, got the authorization cookie all the way to my server (as described here), and was able to verify that the token is indeed signed correctly with my secret key.
Now I'm stuck at the point where I am supposed to take the token I got from JSAPI and exchange it for an access token.
This is the code I'm using, as mentioned it uses Spring Social for Linkedin, and it doesn't work as it throws a 401 Unauthorized response:
LinkedInConnectionFactory connectionFactory =
new LinkedInConnectionFactory(myLinkedinId, myLinkedinSecret);
OAuth1Operations oauthOperations = connectionFactory.getOAuthOperations();
AuthorizedRequestToken art = new AuthorizedRequestToken(new OAuthToken(codeIGotFromJSAPI, aSecretKey), whereDoIGetThisSignature);
OAuthToken accessGrant = oauthOperations.exchangeForAccessToken(art, null);
if (accessGrant == null) return null;
Connection<LinkedIn> connection = connectionFactory.createConnection(accessGrant);
if (connection != null) {
LinkedIn linkedin = connection.getApi();
return linkedin.profileOperations().getUserProfile();
}
What I'm actually confused about is the AuthorizedRequestToken object. The codeIGotFromJSAPI part is simple enough I think, it's just access_token, but what about aSecretKey, is it just my linkedin secret key? what about whereDoIGetThisSignature, how do I create that one? Do I use the same hash method as I used to validate the linkedin response and hash the access_token with my secret linkedin key? In the linkedin page, it says:
You need to pass four values as query parameters:
oauth_consumer_key, to identify yourself
xoauth_oauth2_access_token parameter, set to the value of the access_token field in the cookie.
signature_method set to HMAC-SHA1
signature, calculated as described in the OAuth 1.0a spec
So (1) is automatically done by the connection I suppose, (2) is the access token I provided, but how do I do (3) and (4)?
Lets suppose I get the following data in the JSAPI cookie set by Linkedin:
{
"signature_method":"HMAC-SHA1",
"signature_order": ["access_token", "member_id"],
"access_token":"AD2dpVe1tOclAsNYsCri4nOatfstw7ZnMzWP",
"signature":"73f948524c6d1c07b5c554f6fc62d824eac68fee",
"member_id":"vvUNSej47H"
"signature_version": 1
}
What do I need to do with it to go through the next step?
Use the following process:
Read the cookie
Transform "signature":"..." to &signature=...
Transform "signature_method":"HMAC-SHA1" to &signature_method=HMAC-SHA1
Transform "member_id":"..." to &oauth_customer_key=...
Transform "access_token":"..." to &xoauth_oauth2_access_token=...
Append all to the LinkedIn url plus ?
The LinkedIn JSAPI Token Exchange as described in Exchange JSAPI Tokens for REST API OAuth Tokens is currently not supported by Spring Social, according to a Spring forum discussion on this topic.
But there are implementation available to solve this task without Spring Social by using standard OAuth libraries available for Java. The LinkedIn user's access token, that you get from the exchange, can be put into a new AccessGrant object which can be used to create a Spring Social Connection<?> in the user's ConnectionRepository.
The code published in the LinkedIn developer forum discussion shows how to use Scribe to perform the exchange. The request that has to be sent to LinkedIn is a standard OAuth request but must ship the access_token field from the JSAPI token object as a HTTP query parameter xoauth_oauth2_access_token. The member_id that is also available to you is just for your information, and the signature allows you to verify both access_token and member_id without querying LinkedIn.

How to reset google oauth 2.0 authorization?

I'm using Google APIs Client Library for JavaScript (Beta) to authorize user google account on web application (for youtube manipulations). Everything works fine, but i have no idea how to "logout" user from my application, i.e. reset access tokens.
For example, following code checks user authorization and if not, shows popup window for user to log into account and permit web-application access to user data:
gapi.auth.authorize({client_id: CLIENT_ID, scope: SCOPES, immediate: false}, handleAuth);
But client library doesn't have methods to reset authorization.
There is workaround to redirect user to "accounts.google.com/logout", but this
approach is not that i need: thus we logging user off from google account not only from my application, but also anywhere.
Google faq and client library description neither helpful.
Try revoking an access token, that should revoke the actual grant so auto-approvals will stop working. I assume this will solve your issue.
https://developers.google.com/accounts/docs/OAuth2WebServer#tokenrevoke
Its very simple. Just revoke the access.
void RevokeAcess()
{
try{
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("https://accounts.google.com/o/oauth2/revoke?token="+ACCESS_TOKEN);
org.apache.http.HttpResponse response = client.execute(post);
}
catch(IOException e)
{
}
}
But it should be in asyncTask
It depends what you mean by resetting authorization. I could think of a three ways of doing this:
Remove authorization on the server
Go to myaccount.google.com/permissions, find your app and remove it. The next time you try to sign in you have to complete full authorization flow with account chooser and consent screen.
Sign out on the client
gapi.auth2.getAuthInstance().signOut();
In this way Google authorization server still remembers your app and the authorization token remains in browser storage.
Sign out and disconnect
gapi.auth2.getAuthInstance().signOut();
gapi.auth2.getAuthInstance().disconnect();
This is equivalent to (1) but on the client.
Simply use: gapi.auth.setToken(null);
Solution for dotnet, call below API and pass the access token, doc - https://developers.google.com/identity/protocols/oauth2/web-server#tokenrevoke
string url = "https://accounts.google.com/o/oauth2/revoke?token=" + profileToken.ProfileAccessToken;
RestClient client = new RestClient(url);
var req = new RestRequest(Method.POST);
IRestResponse resp = client.Execute(req);

Resources