Wednesday, May 25, 2022

Using WebAuthenticator with .NET Maui

 First create an authorization callback activity inside the Android assets folder: 

namespace MauiApp6.Platforms.Android
{
    [Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true)]
    [IntentFilter(new[] { Intent.ActionView },
                  Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
                  DataScheme = "ultranomadic")]
    internal class AuthCallbackActivity : WebAuthenticatorCallbackActivity
    {

        public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
        {
            base.OnCreate(savedInstanceState, persistentState);
        }
    }
}

Modify the AndroidManifest.xml file to include this query node inside the manifest node. 

<queries>
<intent>
<action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>

Finally, use the web authenticator to login.  

            WebAuthenticatorResult authResult = await WebAuthenticator.Default.AuthenticateAsync(
                new Uri("https://planner.ultranomadic.com/auth?returnUrl=ultranomadic://planner.ultranomadic.com"),
                new Uri("ultranomadic://"));

            string accessToken = authResult?.AccessToken;

            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
            var json = client.GetStringAsync("https://planner.ultranomadic.com/api/testauthget").Result;

Monday, December 27, 2021

Using Platform Specific Code Inside Xamarin.Forms

First declare an interface in the main project. Something like the following: 

namespace myapp
{
    public interface ILoginService
    {
        void DoLogin(); 
    }
}

Implement the interface in a concrete class inside the android project. 

[assembly: Dependency(typeof(myapp.Droid.AndroidLoginService))]
namespace myapp.Droid
{
    
    class AndroidLoginService : myapp.ILoginService
    {
        public void DoLogin()
        {
            /* implement here */
        }
    }
}

Notice the Dependency attribute. This registers the class with the dependency injection engine in Xamarin. Now you can use the implementation in the main project. 

var loginsvc = DependencyService.Get<ILoginService>();
loginsvc.DoLogin();

Hopefully that helps you use platform specific implementations inside Xamarin.Forms. 

Friday, April 24, 2020

Global error handling in ASPNETCore

Add the following to the StartUp.cs

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

In the controller add the following:

[AllowAnonymous]
public IActionResult Error()
{
    return View(new ErrorViewModel 
        { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}

For access to the exception, use the IExceptionHandlerPathFeature as in the following code:

var exceptionHandlerPathFeature =
    HttpContext.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
{
    ExceptionMessage = "File error thrown";
}
if (exceptionHandlerPathFeature?.Path == "/index")
{
    ExceptionMessage += " from home page";
}

External Authentication in ASPMVC Net Core

In the StartUp.cs file a few additions are needed to make external authorization work. First, this section needs to be added to the ConfigureServices method:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options => {
    options.LoginPath = "/auth";
    options.ReturnUrlParameter = "ReturnUrl";
})
.AddGoogle(options => {
    options.ClientId = "[yourclientid]";
    options.ClientSecret = "[yoursecret]";
    options.CallbackPath = "/auth/signin-google";
    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})

And later on in the Configure method make sure these lines are added.

app.UseAuthentication();
app.UseAuthorization();

Note that /auth/signin-google is not a path supplied by the application. Instead the mvc middleware handles this return and hands control over to /auth/afterauth (as specified in the RedirectUri of the Challenge result. This section goes in the auth controller:

public IActionResult GoogleLogin(string returnUrl= "/")
{
    return new ChallengeResult("Google", new AuthenticationProperties {
        RedirectUri = Url.Content($"/auth/afterauth?provider=Google&returnUrl={returnUrl}")
    });
}

Saturday, April 18, 2020

Easily adding Roles to ASP.NET Core

In the Startup.cs file add the basic authorization middleware. For options, add a new policy. This policy will check for the presence of the admin role claim.

services.AddAuthorization(options => {
   options.AddPolicy("admin", policy => policy.RequireClaim(ClaimTypes.Role,"admin"));
});

In the authentication controller, add the claims to the user.

claims.AddRange(user.Roles.Select(r => new Claim(ClaimTypes.Role, r)));

In the controller you want to secure, add the header to check the policy.

[Authorize("admin")]
public class AdminController : Controller {}

Wednesday, October 30, 2019

Using HTTPS in the ASPNETCORE development server Kestrel

To use SSL with the ASP.net Core development server, Kestrel, first export your certificate to a PFX file. Add the file to your project and then add the following section to your csproj:

  <ItemGroup>
    <None Update="mydomain.pfx">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

This addition will cause the PFX to be coped to your output directory. After adding this to your csproj, add the following section to your appsettings.json file to use the exported certificate:

"Kestrel": {
    "Endpoints": {
        "HttpsInlineCertFile": {
            "Url": "https://test.mydomain.com",
            "Certificate": {
                "Path": "mydomain.pfx",
                "Password": "mypfxpassword"
            }
        }
    }
}

Poof, you're secure.

Saturday, August 10, 2019

Json Serialzation in Entity Framework (EF Core 2.1)

I've had a number of instances where I want to serialize JSON into a single field in the database. In the past I resorted to a [NotMapped] field which held the complex object and a [JsonIgnore]d field which was serialized in EF to a Text SQL field.

I recently discovered that EF Core 2.1 includes easy value conversions! In the example below, I have a Stay entity which has a serialized Drive object. Drive is declared on SQL Server as a Text column.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
   base.OnModelCreating(modelBuilder);


   modelBuilder.Entity<Stay>()
   .Property(s => s.Drive)
   .HasConversion(
      d => JsonConvert.SerializeObject(d),
      d => JsonConvert.DeserializeObject<Drive>(d)
   );
}


Viola! No need for the extra fields on the model class.