Session-like Info in asp.net web service - asp.net

I added a new asp.net project which only hosts (Classic) WebServices on top of my MVC app.
The Web Service calls the Biz Objects which are located in Biz Layer Dlls.
WebService clients are just like the regular users, they have to be authenticated and authorized per operations.
I am using a SOAP authentication token to validate the user upon first call, then passing that token around per following calls.
BizObjects access the IUserSessionManager to get the authorized user, and then call the authorize the user per request. This was pretty easy with the MVC app and the Windows app that the BusinessObjects are called from.
So how do I store user info in the following system where my BusinessObjects can retrieve them from. (This might be easy for you but I am not comfortable working with Web Services)
public class XyzUserSessionManager
{
private static IXyzUserSessionManager _instance;
public static IXyzUserSessionManager UserSessionManager
{
get { return _instance; }
set { _instance = value; }
}
public static IXyzUserSession Current
{
get { return UserSessionManager.Current; }
}
}
public IXyzUserSession Current
{
get
{
if (HttpContext.Current == null || HttpContext.Current.Session == null || HttpContext.Current.Session[SessionKey] == null)
return null;
return (IXyzUserSession)HttpContext.Current.Session[SessionKey];
}
protected set
{
HttpContext.Current.Session[SessionKey] = value;
}
}

You can enable session state support just like for regular web apps. This is done on a per-method base. See more details here: http://msdn.microsoft.com/en-us/library/aa480509.aspx

Related

Need advice of where to put custom user authorization in ASP.NET Core

I need advice of where to put custom user authorization code in ASP.NET Core. I am somewhat a ASP.NET Framework developer and normally I will add code to Global.asax as a session_onstart event to look up a SQL table where users profile are stored that is used to determine what they can view in the rest of the application. With Global.asax this is only cause once per user session, so what I would like to do is the same kind of approach in ASP.NET Core which I am kind of new to but need advice where that check should be done
I would like to do is the same kind of approach in ASP.NET Core which
I am kind of new to but need advice where that check should be done
Well, based on your description, in asp.net core you can achieve that in many ways. For instances, you could set in following places:
program.cs/startup.cs files
Using Middleware file
Using Action Filter
Let's, consider below example using action filter
Role and permissison:
First we are defining the role and the permission.
public enum Role
{
User,
Admin,
SuperAdmin
}
public enum Permission
{
Read,
Create,
Update,
Delete
}
Authorization On Action Filter:
public class AuthorizeActionFilter : IAuthorizationFilter
{
private readonly Role _role;
private readonly Permission _permission;
public AuthorizeActionFilter(Role item, Permission action)
{
_role = item;
_permission = action;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var isAuthorized = context.HttpContext.User.Claims.Any(c => c.Type == _role.ToString() && c.Value == _permission.ToString());
if (!isAuthorized)
{
context.Result = new ForbidResult();
}
}
}
Note: Check your user claim from the HttpContext if that containts either Admin or Read authorization.
Controller:
[Authorize(Role.User, Permission.Read)]
public IActionResult MemberList()
{
var memberList = _context.Members.ToList();
return View(memberList);
}
Output:
You even can implement that using Middleware. Asp.net 6 now providing couple of other mechanism now a days, you could have a look below official implementations as well.
Role-based authorization
Claims-based authorization
Policy-based authorization
Custom Action Filter

How do you determine if the current user is logged into Azure AD in .NET Core 3.1

I have a .NET Core 3.1 program that hosts an Angular 9 app that will be used by users in a company that uses Azure AD. I need to determine if the user is already logged into their Azure AD and if so get some information about them. I would like to determine this before the Angular App is loaded for the user. This is pretty straight-forward in standard Windows AD and .NET but I can't find how to do this with .NET Core and Azure AD.
I've added some pseudo code below to help give an idea of what I'm trying to achieve:
[ApiController]
[Authorize]
[Route("api/[controller]/[action]")]
public class AuthenticationController : ControllerBase
{
public AuthenticationController()
{
}
[AllowAnonymous]
[HttpPost]
public LoginResult Login([FromBody] LoginRequestDC loginRequest)
{
LoginResult lr = new LoginResult();
if (loginRequest != null)
{
try
{
if(NotLoggedInAzureAD)
{
lr = LoginWithUserNameAndPasswordAndGetInfoFromDataBase(loginRequest);
}
else
{
lr.IsLoggedIn = true;
lr.UserInfo = GetInfoFromAzureAD;
}
}
catch (Exception ex)
{
Common.AppLogger.Error(ex, $"Unable to login.");
}
}
return lr;
}
private bool NotLoggedInAzureAD()
{
//Not sure how you would get the Azure AD user in .net core
return CodeToAskAzureADIfUserLoggedIn(MyHttpContext.Current.User.Identity.Name);
}
private UserInfo GetInfoFromAzureAD()
{
return CodeToAskAzureADForUserInfo(MyHttpContext.Current.User.Identity.Name);
}
}
Please help.
Check out the Code Samples page. There are a lot of samples, for example .NET Core Web App. Like this one, which is a .NET Core 3.1.
But I suggest that you first start with Authentication basics, go over Security Tokens, the Application Model and finally understand the App Sign-In Flow in Microsoft Identity Platform.

Pass User info to WCF Web service with WCF method vs with Soap header

My WCF Webservice provide all data manipulation operations and my ASP .Net Web application present the user interface.
I need to pass user information with many wcf methods from ASP .Net app to WCF app.
Which one in is better approach regarding passing user info from web app to web service?
1) Pass user information with SOAP header?
ASP .Net Application has to maintain the number of instances of WCF Webservice client as the number of user logged in with the web application. Suppose 4000 user are concurrently active, Web app has to maintain the 4000 instances of WCF webserice client.
Is it has any performance issue?
2) Pass user information with each method call as an additional parameter?
Every method has to add this addtional paramter to pas the user info which does not seems a elegant solution.
Please suggest.
regards,
Dharmendra
I believe it's better to pass some kind of user ID in a header of every message you send to your WCF service. It's pretty easy to do, and it's a good way to get info about user + authorize users on service-side if needed. And you don't need 4000 instances of webservice client for this.
You just need to create Behavior with Client Message Inspector on client side(and register it in your config). For example:
public class AuthClientMessageInspector: IClientMessageInspector
{
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
request.Headers.Add(MessageHeader.CreateHeader("User", "app", "John"));
return null;
}
}
public class ClientBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
foreach (var operation in endpoint.Contract.Operations)
{
operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = Int32.MaxValue;
}
var inspector = new AuthClientMessageInspector();
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
And extract it from your service-side:
var headers = OperationContext.Current.IncomingMessageHeaders;
var identity = headers.GetHeader<string>("User", "app");

Building ASP.Net custom authorization against database without MVC

this is my first request, so don´t be too hard. :)
We are building an Sharepoint 2010 - Application, which consists of some Sharepoint Web Parts and many ASP.Net-Sites. Therefore we are limited to use ASP.Net without MVC. This decision is made and can´t be refused.
We are using Windows Authentification with Impersonation. The Users are stored in an application database. Along with the users there are roles which have rights to specific objects and specific actions. all these informations are stored in the custom database.
The database has a data access layer (EF 4.0). Because Sharepoint is limited to .NET Framework 3.5, the business logic consists of a WCF Data Service which is using the DAL and business logic libary which accessing the WCF Data Service to grab the required information.
The ASP.Net-Pages and Sharepoint Web Parts are directly accessing the business logic.
What i now need is some kind of a Manager-Class which is checking the user against the database to authorize him to access the specific objects. I dont want to do it programmaticly. I want to use annotations to specify if a method from the business layer can be called or not. Furthermore i want to hide some things in the ASP.Net Sites without an programmaticly if-clause.
Can someone give me a hint to achieve this? Is there a way do customize some part of the standard framework to realize it?
The user and his roles and rights i want to store in a session. Is this a good way? the application is accessible only in local network.
Welcome to stackoverflow! A few thoughts on this -
You may be better suited to ask these questions at the cousin site http://sharepoint.stackexchange.com.
This depends on your web farm architecture. If your web front end and data sources are on the same server, then it should be simple to use windows authentication to determine the current user. However, if your web front ends and data sources are on separate servers, then you've reached a limitation due to the "double hop" scenario, where the user's credentials cannot be shared to the server behind the sharepoint server - so to speak.
To work around, investigate using Kerberos authentication in your SharePoint environment, which allows SharePoint to track user credentials throughout the farm - http://blogs.technet.com/b/tothesharepoint/archive/2010/07/22/whitepaper-configuring-kerberos-authentication-for-sharepoint-2010-and-sql-server-2008-r2-products.aspx
Yet another alternative, don't use SharePoint as your application host. Create your web application and deploy it as its own website (http://mysupercoolsite.organization.com), and in SharePoint create a new "web part page", with a "full page vertical" layout. Then, add a "Page Viewer" web part to the page, supplying the url to mysupercoolsite.organization.com. This way, SharePoint is a "portal" to this application for your users, but all authentication, authorization, and structure are based on the application itself, and not at all in SharePoint.
We have stayed at sharepoint as application host.
I´ve implemented a Custom UserControl which implements all the security questions.
public partial class FMD_RoleEnabledControl : System.Web.UI.UserControl
{
public string EnabledRoles { get; set; }
public bool HasDataBinding { get; set; }
public string CurrentUserName
{
get { return Page.User.Identity.Name; }
}
protected override void OnPreRender(EventArgs e)
{
if (!HasDataBinding)
Visible = EnabledRoles.Split(',').Any(rolle => new FMDRoleProvider().IsUserInRole(CurrentUserName, rolle));
base.OnPreRender(e);
}
protected override void OnLoad(EventArgs e)
{
if(HasDataBinding)
Visible = EnabledRoles.Split(',').Any(rolle => new FMDRoleProvider().IsUserInRole(CurrentUserName, rolle));
base.OnLoad(e);
}
}
Custom-RoleProvider
public class FMDRoleProvider : RoleProvider
{
public const string SEPERATOR = ",";
...
public override string[] GetRolesForUser(string username)
{
if (username == null || username == "")
throw new ProviderException("Kein User-Name übergeben"); //TODO
string tmpRollen = "";
RechteManager rm = new RechteManager();
var rollen = rm.GetUserRollen(username);
foreach (var rolle in rollen)
{
tmpRollen += rolle.ROL_Name + SEPERATOR;
}
if (tmpRollen.Length > 0)
{
//Letzten seperator entfernen
tmpRollen = tmpRollen.Substring(0, tmpRollen.Length - 1);
return tmpRollen.Split(',');
}
return new string[0];
}
...
public override bool IsUserInRole(string userName, string roleName)
{
if (userName == null || userName == "")
throw new ProviderException("User name cannot be empty or null."); //TODO
if (roleName == null || roleName == "")
throw new ProviderException("Role name cannot be empty or null."); //TODO
RechteManager rm = new RechteManager();
return rm.IsUserInRolle(userName, roleName);
}
}
Usage
public partial class CustomControl: FMD_RoleEnabledControl
<custom:CustomControl ID="custom" runat="server" EnabledRoles="Admin" HasDataBinding="True" />
Its only the first approach to check against roles, but it works very well. As a second target i am going to implement extra security stuff like checking against speficic actions. Also the RoleProvider has to be registered in web.config. But time is short ;)

What is the preferred way to access ASP.NET profile in .NET n-tier application?

I have a WPF application which talks to a WCF service hosted in IIS. I am also using ASP.NET authorization and authentication to access the service methods. There is also a relatively thin web based interface to the system as well.
What I want is to make use of the ASP.NET Profiles. For example - load profile from server, make changes and then save back to the server. All that with WCF Service calls.
This is my sample User Profile class which is declared server side. I have also defined the appropriate entries in the web.config so it works properly.
public class UserProfile: ProfileBase
{
public static UserProfile GetUserProfile(string username)
{
return Create(username) as UserProfile;
}
public static UserProfile GetUserProfile()
{
return Create(Membership.GetUser().UserName) as UserProfile;
}
public int? XMLVersion
{
get
{
return this["XMLVersion"] as int?;
}
set
{
this["XMLVersion"] = value;
}
}
}
However I cannot pass it back to the client because ProfileBase is not serializable. Of course I can declare data transfer class which will transfer data back and forth from the profile but it does not look as a very good solution.
So far I am unable to find information how to implement it. Can someone help me with that or point me to another solution?
The WCF profile service does what you are asking for. Have a look at it here.
You can see the list of methods it provides in this MSDN page

Resources