Session usage in WCF service - c#

In my wcf project, I want to store some user information(userid or something) as we use asp.net session.After logging in, the userid will store in session
and we can retrieve it for other service.I found we can use httpcontext.current.session in wcf but that one is only support for wcf hosted in IIS.
My wcf service will be hosted in window service.Is there any way to do? Is there any variable or function in wcf to get that features?
Please guide me the right way.Thanks for your help.
//For example
//LogOnWCFService
public Boolean LogOn(string userID, string PWD)
{
currentUserID = userID;
HttpContext.Current.Session.Add("UserID",userID);
return true;
}
//ProcessWCFService
public void Process()
{
string userid = HttpContext.Current.Session["UserID"].ToString();
if(userid == 1)
{
//Do Something
}
}

I would avoid the use of sessions with WCF, espescially if you want to use the session data over different Service calls.
A better approach would be to implement your own session management. The LogOnService could create an unique sesion ID after a successfull logon and return it to the client. The session ID could be persisted together with additional informations (UserID etc.). All other services then include this session ID in every method call to identitfy itself.
nSess = logscv.LogOn(UserID)....procsvc.Process(nSess)

Related

How to properly access HTTP Headers from your controller? (.NET Web App)

I am currently developing a .NET Web App (MVC), and it is designed such that the user logs into the app in another web app, then the IIS passes control to my web app (I call it SP). SP then needs to access headers passed to it containing user information passed from the login page. These fields are then used to add the user to a database for logging purposes. This behavior is called in the constructor from the main controller of the Web App: HomeController because I would like it to run whenever a user accesses the page.
This is my current implementation:
public HomeController()
{
try
{
string ID = Request.Headers.Get("CN userName");
if (ID.Length > 3)
{
try
{
ID = ID.Substring(3, 3);
}
catch
{
ID = ID.Substring(0, 3);
}
}
string firstName = Request.Headers.Get("X-First Name");
string lastName = Request.Headers.Get("X-Last Name");
string email = Request.Headers.Get("X-Mail");
currUser = new User(ID, firstName, lastName, email, ""); }
catch (Exception e)
{
currUser = new User(/*Create Default User*/);
}
}
The User constructor handles methods needed to manage the User after creation. However, this currently throws an error when deployed when it attempts to access any of the headers. I do not have a lot of experience working with headers so I spent hours attempting to find a solution online, but nothing I tried accomplished what I needed it to. I would appreciate assistance in solving this issue and implementing this behavior properly.
I don't think you should do this in a controllers constructor (not sure it's safe either).
It's probably better suited to an Filter, which will make it far easier to reuse.

How Can Get Session With SessionId?

I use ASP.NET MVC. I have a problem. I set my variables to the session and I request a web service that doesn't belong to me. Then the web service makes an HttpPost request to my server.
It doesn't send a cookie to my server so I lost my session.
I think I can save my sessionid to the DB and I can get back my session with this ID. But I can't get any solution.
What's your suggestion?
public ActionResult SomeAction(){
mySettingService.saveSessionIdToDb(someToken, Session.SessionID);
var myPaymentFormObj = FormInit.Create(request, options);
myPaymentFormObj.DoRequest(); //it's callback to my another action with a token
}
[HttpPost]
public ActionView MyCallBack(string someToken){
//here is our app generates new session id and i lost my session because other server doesn't send me session id.
//i need to read session id from db and i can get my session maybe.
var mySessionId = mySettingService.getSessionIdFromDb(someToken);
//how can i start session like this?
Session.SessionID = mySessionId;
}
It seems like the problem you described is about maintaining the distributed transaction.
To describe it better your app is a service A and the webServer is service B.
You can perform an action which saves some changes to the database A including the session stuff then you send a call to service B which also can saves some changes to its DB or perform a bunch of other actions but in this case you don't care how it works, you only care about what kind of responses you get back with a callback. There should be an option to be able to send some kind of unique thing like userEmail or a transactionId which you can get back in a callback method to be able to recognize the transaction.
What I would suggest you do is something like
[HttpPost]
public ActionResult SendBlah(BlahData data){
var transactionId = Guid.NetGuid();
_sessionService.Create(transactionId, dataYouWantToStore)
_webServiceB.SendBlah(transactionId, data, token);
//optionally return info about call status / do other stuff
}
//or this can be of type HttpGet
[HttpPost]
public ActionView MyCallBack(string someToken, string tranactionId){
var sessionData = _sessionService.Get(tranactionId)
//do other stuff
}
If it's needed and you are using e.g. JWT you can store the transactionId/emailAddress/etc. there instead and read it.
Btw. it's always safer to store the session in the database instead of using some cache objects or relaying on cookies or javascript objects etc.
Also, it's better to be careful with the amount of data you want to store in a Session table in your db. I'd personally focus on storing the Ids and stuff like Status of given item etc.

I wonder why WebSecurity.Login(username,password) returns false while WebSecurity.Exists(username) does return true

I have created WCF project along with MVC. I have implemented SimpleMembership database of default MVC template inorder to register and login user which I was able to implement successfully. However I could not query same database tables i.e. UserProfiels(UserId, UserName), webpages_Membership(UserId,Password, PasswordSalt,....) by using same WebSecurity.Login(UserName,Password) method.
Register Method in MVC Project is as
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
WebSecurity.Login(username,password) method in WCF project is as follows
public string LoginService(string UserName, string Password)
{
try
{
string answer = null;
if (WebSecurity.UserExists(UserName)) // returns true
{
if(WebSecurity.Login(UserName,Password)) // always return false
{
string role = Roles.GetRolesForUser(UserName).FirstOrDefault();
answer = role;
}
}
return answer;
}
catch (Exception)
{
return null;
}
}
I wonder why WebSecurity.Login(UserName,Password) never populates the UserProfile and webpages_Membership table where username and corresponding password exists.
I have not updated any web.config file as it has default setting for db connection and WCF Rest binding which works perfectly.
I had a look here https://msdn.microsoft.com/en-us/library/webmatrix.webdata.websecurity.login(v=vs.111).aspx and searched on google but could not found the satisfactory solution.
Highly appreciate for any code snippet or suggestion.
Thank you
I'm assuming that you're running the the MVC and WCF applications as separate sites, and that you are seeing the users appearing in the database.
By default, if you don't change anything else, ASP.NET will generate a distinct Application Name for each site (see the remarks here), and the users will partitioned by Application - this is probably why you can't log in with the user on the WCF site.
The docs for UserExists state:
The method verifies that the user exists in the user profile table. However, it does not verify that a membership account exists for that user
It would appear that the profiles aren't being partitioned in the same way.
If you set the ApplicationName in the membership configuration, you'll be able to use the same database and logins on both applications.

Web API has no session - need to check if user is authenticated

I'm creating my first WebAPI project, and have hit my first snag. It seems that because the WebAPI model is stateless, I have no Session available to me. So, my attempt to add a session variable when logging in, has failed.
public static void CreateSession(int userId, string firstName, string surname, int timezoneOffset, string timezoneName)
{
// Create the object.
var session = new SessionToken
{
FirstName = firstName,
Surname = surname,
TimezoneName = timezoneName,
TimezoneOffset = timezoneOffset,
UserID = userId
};
// Is there an existing session?
var existing = HttpContext.Current.Session[SESSIONNAME];
// If so, we need to kill it and refresh it. Not sure why we would have this case though.
if (existing != null)
HttpContext.Current.Session.Remove(SESSIONNAME);
// Create the session.
HttpContext.Current.Session.Add(SESSIONNAME, session);
}
Session is null, and this is because of the stateless model used by WebAPI.
How can I achieve this with Web API? How can I have something to check and query to see if the current user is valid? My session would normally hold some items such as the chaps name, to render on the layout screen - but it looks like that isn't possible right now.
The recommended approach is using stateless authentication and authorization with tokens.
Since some years, it's very easy to configure your WebAPI to integrate OAuth2 workflow using an OWIN middleware.
Learn how following this tutorial.
What you call session items, in OAuth2 you talk about claims.

Basic authentication on a remote server

I need some help with ASMX web-services.
Let's suppose I have a ServerService which provides some data. Let's suppose it has a method GetRandomInteger which returns a random integer (obviously). It implements a custom basic authentication using IHttpModule.
public class BasicAuthHttpModule : IHttpModule
{
private UserRepository _userRepository;
public void Dispose()
{
}
public void Init(HttpApplication application)
{
_userRepository = new UserRepository();
application.AuthenticateRequest += OnAuthenticateRequest;
application.EndRequest += OnEndRequest;
}
public void OnAuthenticateRequest(object source, EventArgs e)
{
var app = (HttpApplication)source;
string authHeader = app.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(authHeader))
{
// Here I successfully get credentials from header
if (_userRepository.ValidateUser(username, password)) return;
// Return 401 and CompleteRequest
}
else
{
// Return 401 and End
}
}
public void OnEndRequest(object source, EventArgs eventArgs)
{
if (HttpContext.Current.Response.StatusCode == 401)
{
// Return 401 and require new authorization
}
}
Fortunately, it works. Now I can successfully open Service.asmx file, get basic authentication window and get access to it's GetRandomInteger method after successful authentication.
Now I have an ASP.NET MVC 4 application called ClientService. It must provide user interface with convenient and appropriate access to methods of ServerService. Now it has default controllers like Account and Home, default views etc.
I need this ClientService to authenticate on a ServerService. I mean there will be a Home/Index page with button "Login". I enter login and password there and ClientService tries to authenticate at ServerService. It returns error on fail or authenticates on success providing access to some Home/RandomInt page which will show the integer requested from ServerService. What is the best and the easiest way to do this?
How to implement registration on a ServerService? There is no AllowAnonymous attribute or something at ASMX, so I can't register user because he doesn't have access to any of methods due to 401 error.
Thank you in advance.
P.S. No. I can't use WCF or something else. I need to implement an ASMX web-service.
Update 1: OK, I have learned something new from here
http://www.aspsnippets.com/Articles/How-to-add-reference-of-Web-Service-ASMX-in-ASPNet-using-Visual-Studio.aspx
There is an old-style thing like "Web reference" and it's not an "Service reference". I have added this Web reference to my project and now I can call some methods from this ASMX page in this way:
try
{
ServerService svc = new ServerService();
svc.Credentials = new NetworkCredential("user", "password");
int a = svc.GetRandomInteger();
} catch (WebException e) {
// Auth failed
}
However, I don't understand how to link it with ASP.NET MVC ClientService authentication. So, both questions are still open. Hopefully, I will understand it or you will help me.
Here is a documentation for adding a Web reference to an ASMX Service.
http://www.aspsnippets.com/Articles/How-to-add-reference-of-Web-Service-ASMX-in-ASPNet-using-Visual-Studio.aspx
Using this information I can easily make requests to a web service.
The only thing I left to do on the moment of question update is to create a custom authentication.
When user logins, the client sends a request to a service. In case of successful basic authentication, it creates proper FormsAuthentication cookie ticket for a user. User logs in.
On each request to a service, the client extracts login from FormsAuthentication cookie and his password from server cache and uses them to authenticate on a service. In case of basic auth failure (it can only occur if user's password has been changed on the service side) the cookie is cleared and session is aborted.
Registration is implemented using another one ASMX service which is not using basic auth but is anonymous (because registration is supposed to be anonymous method).
That's it. Finally, I have found a proper solution :)

Categories