AuthorizationManager based on service invocation parameters - wcf-security

I'm currently developing my own AuthorizationManager, it looks something like that:
public class MyAuthorizationManager : ServiceAuthorizationManager
{
static bool initialize = false;
public override bool CheckAccess(OperationContext operationContext)
{
ServiceSecurityContext context = ServiceSecurityContext.Current;
string[] roles = Roles.GetRolesForUser(operationContext.ServiceSecurityContext.PrimaryIdentity.Name);
return roles.Count() > 0;
}
public override bool CheckAccess(OperationContext operationContext, ref System.ServiceModel.Channels.Message message)
{
MessageBuffer buffer = operationContext.RequestContext.RequestMessage.CreateBufferedCopy(int.MaxValue);
message = buffer.CreateMessage();
Console.WriteLine(message);
return base.CheckAccess(operationContext, ref message);
}
}
I would like to perform authorization check based on a service contract parameter, in example, if contract looks like:
[ServiceContract]
public interface IServerContract
{
[OperationContract]
[ServiceKnownType(typeof(ChildTypeOne))]
[ServiceKnownType(typeof(ChildTypeTwo))]
string SecuredMessage(ParentType incoming);
}
My goal is authorizing depending on type, in example, authorizing if incoming date is ChildTypeOne and deniying in case it was ChildTypeTwo.
I've checked "Message" and it looks like:
It must be decrypted
Seems to be highly dependent on binding
Is there any easy way to simply get parameter type?

Ok, i've figured out how to perform that. Anyway, if you know any better way to do so, let me know:
Here is the AuthorizationManager i'm using:
public class MyAuthorizationManager : ServiceAuthorizationManager
{
static bool initialize = false;
public override bool CheckAccess(OperationContext operationContext, ref System.ServiceModel.Channels.Message message)
{
bool returnedValue = base.CheckAccess(operationContext, ref message);
// messags in WCF are always read-once
// we create one copy to work with, and one copy to return back to the plumbing
MessageBuffer buffer = operationContext.RequestContext.RequestMessage.CreateBufferedCopy(int.MaxValue);
message = buffer.CreateMessage();
// get the username vale using XPath
XPathNavigator nav = buffer.CreateNavigator();
StandardNamespaceManager nsm = new StandardNamespaceManager(nav.NameTable);
nav = nav.SelectSingleNode("//#i:type",nsm);
returnedValue &= (nav.ToString() == "a:"+typeof(ChildTypeOne).Name);
return returnedValue;
}
public class StandardNamespaceManager : XmlNamespaceManager
{
public StandardNamespaceManager(XmlNameTable nameTable)
: base(nameTable)
{
this.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
this.AddNamespace("s11", "http://schemas.xmlsoap.org/soap/envelope/");
this.AddNamespace("s12", "http://www.w3.org/2003/05/soap-envelope");
this.AddNamespace("wsaAugust2004", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
this.AddNamespace("wsa10", "http://www.w3.org/2005/08/addressing");
this.AddNamespace("i", "http://www.w3.org/2001/XMLSchema-instance");
}
}
}
Previous AuthorizationManager will work rejecting "ChildTypeTwo". You can use a RoleProvider in order to get role based on type.

Related

SignalR object not keeping state

I have an asp-hosted webasenbly on blazor using SignalR to send data from the server to the client. Here's the server sending a card to the client:
FounderCard cardToSend = LinkedInCards.GetOne();
int ReaminigCards = LinkedInCards.Count;
cardToSend.IsLeaderOfBand= true;
cardToSend.IsSelected = true;
await Hub.Clients.All.SendAsync(MessageOrders.RevealLinkdinCard.ToString(), cardToSend, ReaminigCards);
here's the debug when sending the object, clearly properly filled in:
Here's the receiving client:
hub.On<FounderCard, int>(MessageOrders.RevealLinkdinCard.ToString(), (card, remainig) => {
Game.RevealLinkedinCard(card, remainig);
});
But the object is anew. The values on the enums are the 0 value..
PS: the method work for other complex structures as player data, all fields arrive properly formatted to the destination ...
Just in case it helps, this is the definition of the FounderCard being sent:
public class FounderCard : Card
{
//base clase Card just implements Serialize and INotifyPropertyChanged
public Sections Section;
public Races Race;
public string Color => FounderCommons.FromSectionToColor(this.Section);
public string ID = String.Empty;
public bool IsLeaderOfBand;
public bool IsSelected;
public void SetID(int counter)
{
this.ID = FounderCommons.GetSectionID(this.Section) + "_" + FounderCommons.GetRaceID(this.Race) + "_" + counter.ToString();
}
}
System.Text.Json (the Json library being used by default in SignalR), doesn't serialize fields by default. You either need to change the fields to properties by adding { get; set; }, or you can set the attribute [JsonInclude] on the fields. More info can be found at https://learn.microsoft.com/dotnet/standard/serialization/system-text-json-how-to?pivots=dotnet-6-0#include-fields

Kentor Auth Services choose programmaticaly entityId based on page url

I'm integrating our asp.net MVC application with SAML2 Authentication. And using Kentor.AuthServices as module as described at kentor.AuthServices Configuration
Everithing works fine. But next step is to add usage of second service provider (which configured to use another auth mechanisms on server side) only for specified range of pages.
First, how to configure it via web.config to add second SP (not the second IdP in scope of first SP) with different entityId.
And Second, how to switch programmatically to second SP? I assume that it should happend in global.asax file in method Application_BeginRequest, but how?
Using two different SP instances in the same application is a quite rare scenario. But if you are really sure you need it, it can be achieved.
You will have to use the Kentor.AuthServices.Owin package and do the configuration in code - web.config won't do. Register two instances of the middleware. Each one will have their own configuration, including their own SP EntityID. Also make sure to change the ModulePath of at least one of them so that they get different endpoint addresses.
To challenge an authentication from either one, set the right authentication scheme in the challenge (typically in a ChallengeResult returned from a controller)
Self-answering.
Here is a workaround for multiple SP for MVC or HttpModule package, switching is based on specified range of URLs. In my case different SP realize different amount of security factors.
First, implementing custom IOptions and CookieHandler, with ability to switch to correct instance. In the web.config file, two kentor.authServices sections must be defined. In my case only "entityId" attribute differs.
public class CustomOptions : IOptions
{
private IOptions options1Factor;
private IOptions options2Factor;
private Func<bool> _checkIsSecure;
public CustomOptions(Func<bool> checkIsSecure)
{
_checkIsSecure = checkIsSecure;
AddOption(out options2Factor, "kentor.authServices1");
AddOption(out options1Factor, "kentor.authServices");
}
private void AddOption(out IOptions options, string sectionName)
{
var sp = new SPOptions((KentorAuthServicesSection)ConfigurationManager.GetSection(sectionName));
options = new Options(sp);
KentorAuthServicesSection.Current.IdentityProviders.RegisterIdentityProviders(options);
KentorAuthServicesSection.Current.Federations.RegisterFederations(options);
}
public SPOptions SPOptions
{
get
{
if (_checkIsSecure())
return options2Factor.SPOptions;
return options1Factor.SPOptions;
}
}
public IdentityProviderDictionary IdentityProviders
{
get
{
if (_checkIsSecure())
return options2Factor.IdentityProviders;
return options1Factor.IdentityProviders;
}
}
public KentorAuthServicesNotifications Notifications
{
get
{
if (_checkIsSecure())
return options2Factor.Notifications;
return options1Factor.Notifications;
}
}
}
public class CustomCookieHandler : CookieHandler
{
private Func<bool> _checkIsSecure;
private CookieHandler _originalCookieHandler1Factor;
private CookieHandler _originalCookieHandler2Factor;
public CustomCookieHandler(Func<bool> checkIsSecure)
{
_checkIsSecure = checkIsSecure;
_originalCookieHandler1Factor = new ChunkedCookieHandler()
{
Name = "commonAuth",
RequireSsl = false
};
_originalCookieHandler2Factor = new ChunkedCookieHandler()
{
Name = "securedAuth",
RequireSsl = false
};
}
public override string MatchCookiePath(Uri baseUri, Uri targetUri)
{
if (_checkIsSecure())
return _originalCookieHandler2Factor.MatchCookiePath(baseUri, targetUri);
return _originalCookieHandler1Factor.MatchCookiePath(baseUri, targetUri);
}
protected override void DeleteCore(string name, string path, string domain, HttpContext context)
{
if (_checkIsSecure())
_originalCookieHandler2Factor.Delete();
else
_originalCookieHandler1Factor.Delete();
}
protected override byte[] ReadCore(string name, HttpContext context)
{
if (_checkIsSecure())
return _originalCookieHandler2Factor.Read();
return _originalCookieHandler1Factor.Read();
}
protected override void WriteCore(byte[] value, string name, string path, string domain, DateTime expirationTime, bool secure, bool httpOnly, HttpContext context)
{
if (_checkIsSecure())
_originalCookieHandler2Factor.Write(value, true, expirationTime);
else
_originalCookieHandler1Factor.Write(value, true, expirationTime);
}
}
In Global.asax file setting static properties to custom implementations. No more modifications needed.
protected void Application_Start()
{
FederatedAuthentication.FederationConfiguration.CookieHandler = new CustomCookieHandler(CheckIsSecure);
Kentor.AuthServices.Mvc.AuthServicesController.Options = new CustomOptions(CheckIsSecure);
}
private bool CheckIsSecure()
{
if (HttpContext.Current == null)
return false;
var mainHost = "http://host.local"; // host url
var sp = new [] { "/Home/Secure" }; // array of URLs which must be secured with other SP
var request = HttpContext.Current.Request;
var isSecured = sp.Any(x => x.Equals(request.Path, StringComparison.InvariantCultureIgnoreCase));
if (!isSecured && request.Path.Equals("/AuthServices/SignIn", StringComparison.InvariantCultureIgnoreCase))
{
var returnUrl = request.QueryString["ReturnUrl"];
isSecured = !string.IsNullOrEmpty(returnUrl) &&
sp.Any(x => x.Equals(returnUrl, StringComparison.InvariantCultureIgnoreCase));
}
if (!isSecured && request.Path.Equals("/AuthServices/Acs", StringComparison.InvariantCultureIgnoreCase))
{
var _r = new HttpRequestWrapper(request).ToHttpRequestData();
isSecured = _r != null && _r.StoredRequestState != null && _r.StoredRequestState.ReturnUrl != null
&& sp.Any(x => x.Equals(_r.StoredRequestState.ReturnUrl.ToString(),
StringComparison.InvariantCultureIgnoreCase));
}
if (!isSecured && !string.IsNullOrEmpty(request.Headers["Referer"]))
{
var referer = request.Headers["Referer"];
isSecured = sp
.Select(x => string.Format("{0}/{1}", mainHost.TrimEnd('/'), x.TrimStart('/')))
.Any(x => x.Equals(referer, StringComparison.InvariantCultureIgnoreCase));
}
return isSecured;
}

ASP.Net MVC Constructor Injection with Autofac - Change Runtime ConnectionString [duplicate]

I have a specific scenario here where I need to pass the connection string based on the user, because users may be mapped to the different databases based on his/her enterprise.
This is the code I use to resolve the dependency with a static variable:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IUserRepository>()
.ImplementedBy(typeof(IKS.Dare.Optimix.Repository.EntityFramework.UserModule.UserRepository))
.DependsOn(Dependency.OnValue("connectionString", DatabaseSettings.DefaultConnectionString))
);
}
Because this DefaultConnectionString is supposed to be a dynamic one, I don't want to lock this variable to make it thread safe, as this would degrade the performance. I would want a way so that I can deal with such situation.
Possible consideration which can be that we can give a session, which can be applied as follows:
DynamicParameters((k, d) => d["connectionString"] = Session["connectionString"])
But this is in a different project which doesn't utilize any web component, it's just an installer project which is basically designed for resolving the dependencies only.
My Generic repository looks like following
public class GenericRepository<T> : IGenericRepository<T> where T : BaseEntity
{
private const string IsActive = "IsActive", DbContext = "dbContext", EntityPropertyName = "Entity";
private string connectionString = String.Empty, provider = String.Empty;
public GenericRepository(string connectionString, string provider)
{
this.connectionString = connectionString;
this.provider = provider;
}
public int Count()
{
string tableName = typeof(T).Name;
string query = SqlQueryConstants.SelectCount + SqlQueryConstants.Space + tableName;
int count = DbHelper.ExecuteScalar<int>(query: query, commandType: System.Data.CommandType.Text, connectionString: connectionString, provider: provider, parameters: null);
return count;
}
}
DBHelper class looks like follows
public static int ExecuteNonQuery(string query, CommandType commandType = CommandType.StoredProcedure,
IList<DbParameter> parameters = null, int? timeout = null, string connectionString = "", string provider = "")
{
using (var connection = CreateDbConnection(connectionString, provider))
{
connection.Open();
using (DbCommand command = CreateDbCommand(sqlQuery: query, parameters: parameters,
connection: connection, commandType: commandType, timeout: timeout))
{
return command.ExecuteNonQuery();
}
}
}
public static DbParameter CreateParameter<TValue>(string name, TValue value, DbType dbType,
ParameterDirection parameterDirection = ParameterDirection.Input, string provider = "")
{
DbParameter param = CreateDbProviderFactory(provider).CreateParameter();
param.Value = value;
param.ParameterName = name;
param.DbType = dbType;
param.Direction = parameterDirection;
return param;
}
public static DbConnection CreateDbConnection()
{
return CreateDbConnection(String.Empty, String.Empty);
}
public static DbConnection CreateDbConnection(string connectionString = "", string provider = "")
{
DbConnection connection = null;
if (String.IsNullOrEmpty(provider))
{
if (String.IsNullOrEmpty(DatabaseSettings.DefaultProvider))
throw new ArgumentNullException("provider");
else
provider = DatabaseSettings.DefaultProvider;
}
connection = CreateDbProviderFactory(provider).CreateConnection();
connection.ConnectionString = connectionString;
return connection;
}
Any help would be greatly appreciated.
Note : I couldn't edit steven's answer.
[EDIT] To make it more clear it can be implemented as:
Here controller is inherited from BaseController
public class UserController : BaseController
{
//
// GET: /Index/
private IUserRepository userRepository;
public UserController(IUserRepository userRepository)
: base(userRepository)
{
this.userRepository = userRepository;
}
}
and BaseController is inherited from Controller where in the database settings are being set in the constructor of Base controller so that we don't need to set it everywhere
public abstract class BaseController : Controller
{
public BaseController(IUserRepository userRepository)
{
userRepository.connectionStringProvider.Provider = WebUtilities.CurrentUserData.Provider;
userRepository.connectionStringProvider.ConnectionString = WebUtilities.CurrentUserData.ConnectionString;
}
}
Since, the connection string is runtime data, you should not use it to construct your application components, as is described in this article. So as the article advices, you should hide the connection string behind a provider abstraction. For instance:
public interface IConnectionStringProvider {
string ConnectionString { get; }
}
This way your repositories can depend on IConnectionStringProvider and can call IConnectionStringProvider.ConnectionString at runtime:
public int Count()
{
string tableName = typeof(T).Name;
string query = SqlQueryConstants.SelectCount + SqlQueryConstants.Space + tableName;
return DbHelper.ExecuteScalar<int>(
this.connectionStringProvider.ConnectionString,
provider: provider, parameters: null);
}
It will be trivial to create an IConnectionStringProvider to will get the correct connection string for you:
class DatabaseConnectionStringProvider : IConnectionStringProvider
{
public string ConnectionString => Session["connectionString"];
}
Since this clas depends on application-specifics (the ASP.NET session in this case), the class should not be part of the application's core logic. Instead, this adapter should live in the application's start up path (a.k.a. the composition root, the place where you configure your container).
You might even want to consider not passing along the IConnectionStringProvider into your repositories, but instead create an abstraction that will create a connection itself. This will hide the fact that there is a connection string completely.
What you're looking for is multi tenancy. You can google "castle windsor multi tenancy" and find a number of useful articles.
Here's a similar Stackoverflow question that links to some good articles on Windsor and multi tenancy. In particular, look into Windsor's IHandlerSelector interface.

Only allow Nancy to return json or Xml and 406 when accept header is html

I'm writing a Nancy endpoint and I want to do something that I think should be really simple. I want to support returning the content in either json or xml but when html or any other type is requested to return a 406 Not supported. I can easily force either XML or JSON only, and I guess I could do and if (accept is html) return 406 but I would assume that there is some support for this in the content Negotiation support.
Can anybody shed any light?
Implement your own IResponseProcessor, Nancy will pick it up and hook in the engine.
public sealed class NoJsonOrXmlProcessor : IResponseProcessor
{
public ProcessorMatch CanProcess(MediaRange requestedMediaRange, dynamic model, NancyContext context)
{
if (requestedMediaRange.Matches("application/json") || requestedMediaRange.Matches("aaplication/xml"))
{
//pass on, so the real processors can handle
return new ProcessorMatch{ModelResult = MatchResult.NoMatch, RequestedContentTypeResult = MatchResult.NoMatch};
}
return new ProcessorMatch{ModelResult = MatchResult.ExactMatch, RequestedContentTypeResult = MatchResult.ExactMatch};
}
public Response Process(MediaRange requestedMediaRange, dynamic model, NancyContext context)
{
return new Response{StatusCode = HttpStatusCode.NotAcceptable};
}
public IEnumerable<Tuple<string, MediaRange>> ExtensionMappings { get; private set; }
}
We avoided the use of ResponseProcessor for the whole reason that the request was still being run all the way through our authentication layer, domain layer, etc. We wanted a way to quickly kill the request as soon as possible.
What we ended up doing was performing the check inside our own Boostrapper
public class Boostrapper : DefaultNancyBootstrapper
{
protected override void RequestStartup(TinyIoCContainer requestContainer, IPipelines pipelines, NancyContext context)
{
base.RequestStartup(requestContainer, pipelines, context);
pipelines.BeforeRequest += nancyContext =>
{
RequestHeaders headers = nancyContext.Request.Headers
if (!IsAcceptHeadersAllowed(headers.Accept))
{
return new Response() {StatusCode = HttpStatusCode.NotAcceptable};
}
return null;
}
}
private bool IsAcceptHeadersAllowed(IEnumerable<Tuple<string, decimal>> acceptTypes)
{
return acceptTypes.Any(tuple =>
{
var accept = new MediaRange(tuple.Item1);
return accept.Matches("application/json") || accept.Matches("application/xml");
});
}
}

Using moq to verify a method is called in a repository

I asked this question earlier about testing a controller action and verifying that a method in my repository was being called. The answer came back that I should be testing a Save method which is called inside the Register method (both in the same repository) in a seperate test on the repository only. That's what I thought, but I'm coming to do the test and I can't get it to work. :(
Here's the repository test, where am I going wrong?
[TestMethod]
public void Register_calls_Save_method_when_Member_is_valid()
{
_mockMemberRepository.Setup(r => r.GetByEmail(It.IsAny<string>())).Returns((Member)null);
MembershipCreateStatus status = _mockMemberRepository.Object.Register(_testMember.Email, "password", "password");
_mockMemberRepository.Verify(r => r.Save(It.IsAny<Member>()), Times.Once());
}
Here's the Register method on the repository:
public MembershipCreateStatus Register(string email, string password, string confirm)
{
if (password.Equals(confirm))
{
try
{
Member m = GetByEmail(email);
if (m == null)
{
int format = (int)PasswordFormatEnum.Encrypted;
string salt = GenerateSalt();
string pass = EncodePassword(password, format, salt);
m = new Member()
{
Email = email,
Password = pass,
PasswordSalt = salt,
PasswordFormat = format
};
Save(m);
return MembershipCreateStatus.Success;
}
else
return MembershipCreateStatus.DuplicateEmail;
//"A user with that email address already exists. Please use the Forgotten Password link if you need to recover your password.";
}
catch (Exception ex)
{
_logger.LogError(ex);
return MembershipCreateStatus.ProviderError;
}
}
return MembershipCreateStatus.InvalidPassword;
}
You can't use Moq to verify that you're calling one method on an object from another method on that object. What you can do is verify that something that is called in your Save() method is called.
For example, if I was writing my own repository that was using Ado.Net to update a database I could do something like the following:
public class MyRepository : IRepository {
private readonly IDatabase m_db;
public MyRepository(IDatabase myDatabase){
m_db = myDatabase;
}
public void Register(string email, string password, etc.){
// ... do stuff ...
Save(m);
// ... do stuff ...
}
public void Save(Member member){
// ... build sql query ...
m_db.ExecuteNonQuery(sqlCommand);
}
}
You'd then pass a mocked database object to your repository in your test and you'd verify that:
[TestMethod]
public void Register_calls_Save_method_when_Member_is_valid()
{
Mock<IDatabase> _mockDB = new Mock<IDatabase>();
// Setup mockDB with return values for GetByEmail(), etc.
_repository = new MyRepository(_mockDB.Object);
MembershipCreateStatus status = _repository.Register("Email#Email.com", "password", "password");
_mockDB.Verify(r => r.ExecuteNonQuery(It.IsAny<SqlCommand>()), Times.Once());
}
So, you're not verifying that Save() is called explicitly, but by verifying that the right underlying database call was called you can verify that Save() happened.
The same approach should work for other frameworks too.

Resources