OpenRasta - Scott Littlewoods Basic Authentication working example - rest

I'm testing out the feasibility of using OpenRasta as a viable alternative to ASP.NET MVC.
However, I've run into a stumbling block regarding authentication.
Let me be clear, "Open Digest Authentication" is NOT an option at this point.
I've read that Scott Littlewood created a basic authentication fork for OpenRasta and I've downloaded the source from git and successfully built it.
I'm now trying to get the authentication working, so if someone has a real working model, I would be very grateful. Here's what I've done so far:
//Authentication.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using OpenRasta;
using OpenRasta.Configuration;
using OpenRasta.Authentication;
using OpenRasta.Authentication.Basic;
using OpenRasta.Configuration.Fluent;
using OpenRasta.DI;
namespace myOpenRastaTest.Extensions
{
public static class ExtensionsToIUses
{
public static void BasicAuthentication<TBasicAuthenticator>(this IUses uses) where TBasicAuthenticator : class, IBasicAuthenticator
{
uses.CustomDependency<IAuthenticationScheme, BasicAuthenticationScheme>(DependencyLifetime.Transient);
uses.CustomDependency<IBasicAuthenticator, TBasicAuthenticator>(DependencyLifetime.Transient);
}
}
public class CustomBasicAuthenticator : IBasicAuthenticator
{
public string Realm { get { return "stackoverflow-realm"; } }
public CustomBasicAuthenticator()
{
}
public AuthenticationResult Authenticate(BasicAuthRequestHeader header)
{
/* use the information in the header to check credentials against your service/db */
if (true)
{
return new AuthenticationResult.Success(header.Username);
}
return new AuthenticationResult.Failed();
}
}
}
Now to test it I just created an instance of CustomBasicAuthenticator in my HomeHandler.cs:
//HomeHandler.cs
using System;
using myOpenRastaTest.Resources;
namespace myOpenRastaTest.Handlers
{
public class HomeHandler
{
public object Get()
{
var custAuth = new myOpenRastaTest.Extensions.CustomBasicAuthenticator();
return new HomeResource();
}
}
}
So, I need to know what steps i need to take next, hence the reason for me asking for a real working model and not just theory answers since I've just stumbled upon the framework 2 days ago and might not know all the OpenRasta framework,RESTful lingo that you might throw back at me :)
Once I get a grasp of authentication, I'll have a good indication as to how to proceed with my evaluation of whether to port an existing asp.net prototype portal to OpenRasta or not.
Thanks in advance...

I have a sample application using the new OpenRasta authentication process that ONLY supports BASIC authentication at the moment.
Plugging in different authentication schemes should be quite straight forward but I haven't had the time recently to do this.
See this github discussion for future reference: https://github.com/scottlittlewood/openrasta-stable/commit/25ee8bfbf610cea17626a9e7dfede565f662d7bb#comments
For a working example checkout the code here: https://github.com/scottlittlewood/OpenRastaAuthSample
Hope this helps

Once you have an authentication in place, you need it to be triggered by having authorization on one of your resource handlers, which you can do by adding a RequiresAuthentication attribute on it for example.
You can have a look at the code for that attribute to see how to implement custom authorization yourself.

Related

Using interfaces in dependency injection in .Net MAUI

I am trying to implement dependency injection for the first time in my new project in .Net MAUI. For testing purposes, I want to fetch data from a local source in my ViewModel. The production scenario will fetch data from the remote data source using HttpClient.
Below is my code base structure:
I have an Interface:
public interface IApiService
{
Task<bool> GetSomething(string parameter);
Task<string> GetSomethingElse(string parameter);
}
I have two classes that derive from it.
public class LocalDataStore: IApiService
public class RemoteDataStore: IApiService
In my MauiProgram.cs, when I want to use Local Data Store:
builder.Services.AddSingleton<LocalDataStore>()
builder.Services.AddSingleton<IApiService>()
And for Remote Data Store
builder.Services.AddSingleton<RemoteDataStore>()
builder.Services.AddSingleton<IApiService>()
In my ViewModel:
public class Page1ViewModel
{
public Page1ViewModel(IApiService localDataStore)
{
var items = Task.Run(async () => await localDataStore.GetSomething(true));
}
}
While running the app, I get an error :
System.InvalidOperationException: 'Unable to resolve service for type '...IApiService' while attempting to activate 'ViewModels.Page1ViewModel'.'
What am I doing wrong or what else should I be doing?
Kindly help.
Thanks, and regards.
Edit*
Of course, it works if I use LocalDataStore or RemoteDataStore instead of IApiService, when I register the services with the builder. But then if I have to change from one data store to another, I will have to change that in all the ViewModel classes?
It was trivial.
I needed to register the service like so :
builder.Services.AddSingleton<IApiService,LocalDataStore>();
Thanks to https://youtu.be/paZNvvUNFi0, I realised that.
Hope this helps someone.

How to create logfile for each API using Serilog in .Net Framework?

I have created .Net Web API project using 4.6.2 Framework. I am using Serilog within my application. As of now its a Static Class as below.
public static class Logger
{
private static readonly ILogger _logger;
static A1Logger()
{
_logger = new LoggerConfiguration()
.WriteTo.File(("C:/logs/log-.txt"), rollingInterval: RollingInterval.Day)
.CreateLogger();
}
public static void LogError(string error)
{
//_logger.ToJSON(error);
_logger.Error(error);
}
public static void LogInformation(string info)
{
_logger.Information(info);
}
}
It creates log file and also logs information. However I want to create Logfile for each API.
For example If I Hit http://localhost:52137/Controller/sessions It should create Sessions Logfile and should log inside that file and If I hit http://localhost:52137/Controller/Event API it should create Event Logfile and start logging inside it.
RollingInterval should be as above in my Static class. I checked a lot on google there are lot of example for .NetCore fir Serilogs but I couldn't see anything much on .NET Framework. I think I have to use Filter as per my research however I am not sure how can I configure it in .Net Framework. Also, I think Static class wont help me to create multiple log files. Also logfile operation should be asynchronous.
Thank you in advance for your help and If you need some more information about please let me know.
I can't comment so I'll post here.
Take a look at this other question.
It shows you how to filter based on the request path, using serilog-expressions.
Essentially, add configuration to filter the logs by the path.
In code:
Log.Logger = new LoggerConfiguration()
.Filter.ByIncludingOnly("RequestPath like '/Event API%'")
.WriteTo.File("path/to/file/Event API.log");
in JSON:
"Filter": {
"Name": "ByIncluding",
"Args": {
"expression": "RequestPath like '/Event API%'"
}
}
"WriteTo": "File",
"Path": "path/to/files/Event API.log"
You can do this for each application you expect to use this logging library.
You may also be able to build these paths and expressions dynamically, based on incoming requests, so that it creates the files if they don't exist, but I don't have experience doing this.

Performing Explicit Route Mapping based upon Web Api v2 Attributes

I'm upgrading a custom solution where I can dynamically register and unregister Web Api controllers to use the new attribute routing mechanism. However, it seems to recent update to RTM break my solution.
My solution exposes a couple of Web Api controllers for administration purposes. These are registered using the new HttpConfigurationExtensions.MapHttpAttributeRoutes method call.
The solution also allows Web Api controllers to be hosted in third-party assemblies and registered dynamically. At this stage, calling HttpConfigurationExtensions.MapHttAttributeRoutes a second time once the third-party controller is loaded would raise an exception. Therefore, my solution uses reflection to inspect the RoutePrefix and Route attributes and register corresponding routes on the HttpConfiguration object.
Unfortunately, calling the Web Api results in the following error:
"No HTTP resource was found that matches the request URI".
Here is a simple controller that I want to use:
[RoutePrefix("api/ze")]
public sealed class ZeController : ApiController
{
[HttpGet]
[Route("one")]
public string GetOne()
{
return "One";
}
[HttpGet]
[Route("two")]
public string GetTwo()
{
return "Two";
}
[HttpPost]
[Route("one")]
public string SetOne(string value)
{
return String.Empty;
}
}
Here is the first solution I tried:
configuration.Routes.MapHttpRoute("ZeApi", "api/ze/{action}");
Here is the second solution I tried:
var type = typeof(ZeController);
var routeMembers = type.GetMethods().Where(m => m.IsPublic);
foreach (MethodInfo method in routeMembers)
{
var routeAttribute = method.GetCustomAttributes(false).OfType<RouteAttribute>().FirstOrDefault();
if (routeAttribute != null)
{
string controllerName = type.Name.Substring(0, type.Name.LastIndexOf("Controller"));
string routeTemplate = string.Join("/", "api/Ze", routeAttribute.Template);
configuration.Routes.MapHttpRoute(method.Name, routeTemplate);
}
}
I also have tried a third solution, whereby I create custom classes that implement IHttpRoute and trying to register them with the configuration to no avail.
Is it possible to use legacy-style route mapping based upon the information contained in the new routing attributes ?
Update
I have installed my controller in a Web Application in order to troubleshoot the routing selection process with the Web Api Route Debugger. Here is the result of the screenshot:
As you can see, the correct action seems to be selected, but I still get a 404 error.
Update2
After further analysis, and per Kiran Challa's comment below, it seems that the design of Web Api prevents mixing attribute routing and conventional routing, and that what I want to do is not possible using this approach.
I have created a custom attribute [RouteEx] that serves the same purpose of the Web Api [Route] attribute, and now my code works perfectly.
I guess, since this is not possible using the conventional attribute routing, none of the answers on this question could legitimately be consisered valid. So I'm not nominating an answer just yet.
You shouldn't be required to use reflection and inspect the attribute-routing based attributes yourself. Attribute routing uses existing Web API features to get list of controllers to scan through.
Question: Before the switch to attribute routing, how were you loading these assemblies having the
controllers?
If you were doing this by IAssembliesResolver service, then this solution should work even with attribute routing and you should not be needing to do anything extra.
Regarding your Update: are you calling MapHttpAttributeRoutes?

Zend Framework website.com/username

One of the application I am developing using Zend Framework requires the user's profile page to be accessed via website.com/username, while other pages should be accessed by website.com/controller_name/action_name
I am not too sure how can this be achieved, however, I feel this can be done with some tweaks in the .htaccess file.
Can someone here please help me out?
Many thanks in advance
As suggested before, you can use a custom route that will route single level requests. However, this will also override the default route. If you're using modules, this will no longer work example.com/<module>.
I have done this before but only for static pages. I wanted this:
example.com/about
instead of this:
example.com/<some-id>/about
while maintaining the default route so this still works
example.com/<module>
example.com/<controller>
The way I did this was using a plugin to test if my request could be dispatched. If the request could not be dispatched using the default route, then I would change the request to the proper module to load my page. Here is a sample plugin:
class My_Controller_Plugin_UsernameRoute extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$dispatcher = Zend_Controller_Front::getInstance()->getDispatcher();
if (!$dispatcher->isDispatchable($request)) {
$username = $request->getControllerName();
$request->setModuleName('users');
$request->setControllerName('dashboard');
$request->setActionName('index');
$request->setParam('username', $username);
/** Prevents infinite loop if you make a mistake in the new request **/
if ($dispatcher->isDispatchable($request)) {
$request->setDispatched(false);
}
}
}
}
What about using Zend_Controller_Router_Route, look here the link http://framework.zend.com/manual/en/zend.controller.router.html#zend.controller.router.routes.standard.variable-requirements

using action helpers in Zend Framework 1.8

Hi am starting off with Zend Framework and have a question about action helpers. My first application is a simple authentication system (following a tutorial from a book). The registration and authentication seems to work fine but the redirect doesn't.
I have a customer controller that has this among others:
class CustomerController extends Zend_Controller_Action
{
// some code here......
public function authenticateAction()
{
$request = $this->getRequest();
if (!$request->isPost()) {
return $this->_helper->redirector('login');
}
// Validate
$form = $this->_forms['login'];
if (!$form->isValid($request->getPost())) {
return $this->render('login');
}
if (false === $this->_authService->authenticate($form->getValues())) {
$form->setDescription('Login failed, please try again.');
return $this->render('login');
}
return $this->_helper->redirector('index');
}
the authenticate url is http://localhost/customer/authenticate and this seems to work fine but it does not redirect. After authentication I get a blank page which looks like its taking me to the index and just sits there. I tried using '/index' instead but that did not help either. Do I need to do anything special to make the redirector helper work? I have a logout action which behaves the same.
You should call
$this->_helper->redirector('index');
without the return.
I found out there may be a problem with my setup. The code above is perfect, works on another computer.