I have added a UserNamePasswordValidator class to my WCF Service. It appears to work fine. The FaultException and custom error message appears as expected when I supply wrong credentials. And it passes without an exception with correct credentials.
My problem is that I cannot hit a breakpoint placed within the Validate method. I can hit breakpoints everywhere else in the project.
Any suggestions? Test code is below:
using System.IdentityModel.Selectors;
using System.ServiceModel;
namespace WcfTestService1
{
public class Service1Authenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (!(userName == "testUser" && password == "testPassword"))
{
//Specific Exception
//throw new SecurityTokenException("Invalid Username or Password");
//Or Specific Message
throw new FaultException("Custom message to prove this works");
}
}
}
}
Related
I am currently working on implementing some Apis using swagger/swashbuckle in net core 7 and implementing some error handling, I've gone down the route of using an exception handler. With separate endpoints from dev/prod.
E.g. Startup.cs
if (env.IsDevelopment())
{
...details ommited
app.UseExceptionHandler("/dev-error");
}
else
{
...details ommited
app.UseExceptionHandler("/error");
}
ErrorController.cs
[AllowAnonymous]
[ApiExplorerSettings(IgnoreApi = true)]
public class ErrorController : Controller
{
private ILogger _logger;
public ErrorController(ILogger logger)
{
_logger = logger;
}
[Route("dev-error")]
public IAttempt DevError()
{
var context = HttpContext.Features.Get<IExceptionHandlerFeature>();
var exception = context.Error;
return Attempt.Fail(exception);
}
[Route("error")]
public IAttempt Error()
{
var context = HttpContext.Features.Get<IExceptionHandlerFeature>();
var exception = context.Error;
_logger.Log(LogLevel.Error, exception, exception.Message);
switch (exception)
{
case UnauthorizedAccessException:
Response.StatusCode = (int) HttpStatusCode.Unauthorized;
return Attempt.Fail("Unauthorised");
default:
Response.StatusCode = (int) HttpStatusCode.InternalServerError;
return Attempt.Fail("Generic Error");
}
}
}
The idea is that all responses are of IAttempt, so that the FE user can check if its succeeded etc. and whether to handle the result or exception in a user friendly way.
This has been working great up until now when I've been implementing Api's that require the model to be validated. I wanted to amend the IAttempt class to provide modelstate feedback, however I have tried many approaches and cant seem to get modelstate validation flow through the exception handler.
I wanted to implement a custom ValidationException that contains the errors which is then handled in these controllers. But when an exception is thrown in either an IActionFilter or when overriding the InvalidModelStateResponseFactory the exception isn't caught by the exception handler.
Is there a work around? Am I missing something?
Alternatively I could define a InvalidModelStateResponseFactory that returns a similar model(IAttempt), but it would be nice for Failed requests to be handled in one place.
Cheers in advance
I think you can make the InvalidModelStateResponseFactory redirect to the ErrorController, sending the required data to create your response
According to your description, I suggest you could consider using the customer action filter to achieve your requirement.
Inside the custom action filter, we could get the model state's results, then you could throw the exception inside it.
More details, you could refer to below codes:
1.Create the custom action filter:
public class CustomValidationActionFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
if (!context.ModelState.IsValid)
{
var errorList = context.ModelState.Values
.SelectMany(m => m.Errors)
.Select(m => m.ErrorMessage)
.ToList();
throw new Exception();
}
}
public void OnActionExecuting(ActionExecutingContext context) { }
}
2.Inside the program.cs
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new CustomValidationActionFilter());
});
Then if it thrown the exception, it will go to the controller's error action method, since you set the global exception handler.
I was unnecessarily over complicating things so I have dropped what I attempted to do as in theory responses should be handled accordingly to their response status code rather then the object thats passed in.
I am trying to implement ELMAH in a webapi project,since I am new to this elmah technique,I am not able to implement the entire thing.I even tried to follow the sample codes in web but still I am not getting.
can someone please help me to achieve a proper working solution with elmah.
I will be very thankful if a working solution is provided for demo purpose which will be really helpful for me to understand
Here are the steps to send error emails using Elmah
Install Elmah Nuget Package
Update config file to use proper SMTP settings. Here is the example of config file settings
< security allowRemoteAccess="false" />
< errorMail subject="Production Error - {1}: {0}" smtpServer="server address" from="me#you.com" to="you#me.com" />
Create ExceptionLogger class. Here is the example of it
public class ElmahExceptionLogger : ExceptionLogger
{
private const string HttpContextBaseKey = "MS_HttpContext";
public override void Log(ExceptionLoggerContext context)
{
// Retrieve the current HttpContext instance for this request.
HttpContext httpContext = GetHttpContext(context.Request);
// Wrap the exception in an HttpUnhandledException so that ELMAH can capture the original error page.
Exception exceptionToRaise = new HttpUnhandledException(message: null, innerException: context.Exception);
ErrorSignal signal;
if (httpContext == null)
{
signal = ErrorSignal.FromCurrentContext();
// Send the exception to ELMAH (for logging, mailing, filtering, etc.).
signal.Raise(exceptionToRaise);
}
else
{
signal = ErrorSignal.FromContext(httpContext);
signal.Raise(exceptionToRaise);
}
}
private static HttpContext GetHttpContext(HttpRequestMessage request)
{
HttpContextBase contextBase = GetHttpContextBase(request);
if (contextBase == null)
{
return null;
}
return ToHttpContext(contextBase);
}
private static HttpContextBase GetHttpContextBase(HttpRequestMessage request)
{
if (request == null)
{
return null;
}
object value;
if (!request.Properties.TryGetValue(HttpContextBaseKey, out value))
{
return null;
}
return value as HttpContextBase;
}
private static HttpContext ToHttpContext(HttpContextBase contextBase){return contextBase.ApplicationInstance.Context; } }
Register ElmahExceptionLogger class with Web API in startup.cs
config.Services.Add(typeof(IExceptionLogger), new ElmahExceptionLogger());
Even though the answer by #Paresh works, you should use the Elmah.Contrib.WebApi package, since that includes everything needed to use ELMAH with Web API.
I've written a guide to install ELMAH with Web API. Basically you will install the ELMAH and Elmah.Contrib.WebApi packages and then configure it like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
...
config.Services.Add(typeof(IExceptionLogger), new ElmahExceptionLogger());
...
}
}
Regarding the mail configuration, you can validate your web.config using the ELMAH Configuration Validator.
I am working on an MVC site that has some pages that need authentication and others that don't. This is determined using the Authorize and AllowAnonymous attributes in a pretty standard way. If they try to access something restricted they get redirected to the login page.
I'm now wanting to add the functionality to automatically log them in using an encrypted token passed in the querystring (the link will be in emails sent out). So the workflow I want now is that if a request goes to a page that is restricted and there is a login token in the querystring I want it to use that token to log in. If it logs in successfully then I want it to run the original page requested with the new logged in context. If it fails to log in then it will redirect to a custom error page.
My question is where would I need to insert this logic into the site?
I have seen some suggestions on subclassing the Authorize attribute and overriding some of the methods but I'm not 100% sure how to go about this (eg what I would override and what I'd do in those overridden methods.
I've also had a look at putting the logic at a controller level but I am led to understand that the authorize attribute would redirect it away from the controller before any code in the controller itself was run.
It would be better to write a custom authorization attribute that will entirely replace the default functionality and check for the query string parameter and if present, decrypt it and authenticate the user. If you are using FormsAuthentication that would be to call the FormsAuthentication.SetAuthCookie method. Something along the lines of:
public class TokenAuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
string token = filterContext.HttpContext.Request["token"];
IPrincipal user = this.GetUserFromToken(token);
if (user == null)
{
this.HandleUnAuthorizedRequest(filterContext);
}
else
{
FormsAuthentication.SetAuthCookie(user.Identity.Name, false);
filterContext.HttpContext.User = user;
}
}
private IPrincipal GetUserFromToken(string token)
{
// Here you could put your custom logic to decrypt the token and
// extract the associated user from it
throw new NotImplementedException();
}
private void HandleUnAuthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Shared/CustomError.cshtml",
};
}
}
and then you could decorate your action with this attribute:
[TokenAuthorize]
public ActionResult ProcessEmail(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
}
I am working with asp.net WebAPI and I need to create a custom ActionFilter that does a quick check to see if the user requesting the URI should actually be able to get data back.
They have already been authorized to use the web service via basic auth and their role has been validated via a custom role provider.
The last thing I need to do is to check that they have permission to view the data they are requesting with a parameter in their URI.
Here is my code:
public class AccessActionFilter : FilterAttribute, IActionFilter
{
public System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage>> continuation)
{
var result = //code to see if they have permission returns either 0 or 1
if (result==0) {
throw new ArgumentException("You do not have access to this resource");
}
return continuation();
}
}
Currently I just throw an error which is not what I want, I'd rather return System.Net.HttpStatusCode.Unauthorized but I am a little miffed by the method I am overriding and I do not really understand it completely.
How would I go about returning that value?
You are probably best sticking to an exception but using the HttpResponseException which will return an Http status code too.
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized));
Good question here about this.
p.s.
It may be simpler/cleaner to implement ActionFilterAttribute
public class AccessActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var result = //code to see if they have permission returns either 0 or 1
if (result==0)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized));
}
base.OnActionExecuting(actionContext);
}
}
Instead of throwing exception you can set status code
public class ExecutionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var result = 0;//code to see if they have permission returns either 0 or 1
if (result == 0)
{
actionContext.Response = new HttpResponseMessage()
{
StatusCode = HttpStatusCode.Unauthorized,
Content = new StringContent("Unauthorized User")
};
}
base.OnActionExecuting(actionContext);
}
}
I have created a multi-endpoint WCF service and consumed and it is working fine.
But when I am trying to close the service client then am getting error.
This is how I am creating the client object and disposing its working fine for single endpoint WCF service
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
ICardPrintingService Service = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Service = new CardPrintingServiceClient();
var response = this.Service.GetCardData(new GetCardDataRequest { NIK = 6666620501740003 });
try
{
((CardPrintingServiceClient)Service).Close();
}
catch (Exception ex)
{
MessageBox.Show("error");
}
}
}
}
This is going to the catch block when closing the connection with error message
The remote endpoint no longer recognizes this sequence. This is most
likely due to an abort on the remote endpoint. The value of
wsrm:Identifier is not a known Sequence identifier. The reliable
session was faulted.
Can some one tell me why?
Thanks a ton in adv
Raghavendra
What is the need of casting overhere.
((CardPrintingServiceClient)Service).Close(); //pls explain this.
you can try this in finally block.
if (Service.State != System.ServiceModel.CommunicationState.Closed)
{
Service.Abort();
}