hangfire dashboard on staging machine throws a 401 Unauthorized

sam
sam
154 Points
67 Posts

I'm using hangfire in .netcore api project. Everything  working fine but dashboard not appearing on staging environment. In the local machine it's working fine. 

On staging is showing "HTTP ERROR 401".

Views: 21075
Total Answered: 4
Total Marked As Answer: 1
Posted On: 01-Jun-2018 00:40

Share:   fb twitter linkedin
401 means unauthorised access. You need setup authorization mechanism in your code.
 - beginer  15-Jun-2018 04:54
Answers
Smith
Smith
Moderator
738 Points
154 Posts
         

Hi, I also have read the documentation about authorization but didn’t understand how to allow access to everybody or what users and roles are mentioned in docs?

Users = "admin, superuser", // allow only specified users
Roles = "admins" // allow only specified roles

where are they being created and managered?

Posted On: 23-Jun-2018 06:11
Jak
Jak
Member
404 Points
167 Posts
         
Posted On: 23-Jun-2018 06:14
Brian
Brian
Moderator
694 Points
92 Posts
         

Interface IDashboardAuthorizationFilter available, we can implement it something like (Basic Authentication):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Security.Cryptography;
using System.Collections;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;

public class DashboardAuthorization : IDashboardAuthorizationFilter
    {
        public IEnumerable<HangfireUserCredentials> Users { get; }

        public DashboardAuthorization(IEnumerable<HangfireUserCredentials> users)
        {
            Users = users;
        }

        public bool Authorize(DashboardContext dashboardContext)
        {
            var context = dashboardContext.GetHttpContext();

            string header = context.Request.Headers["Authorization"];

            if (!string.IsNullOrWhiteSpace(header))
            {
                AuthenticationHeaderValue authValues = AuthenticationHeaderValue.Parse(header);

                if ("Basic".Equals(authValues.Scheme, StringComparison.InvariantCultureIgnoreCase))
                {
                    string parameter = Encoding.UTF8.GetString(Convert.FromBase64String(authValues.Parameter));
                    var parts = parameter.Split(':');

                    if (parts.Length > 1)
                    {
                        string username = parts[0];
                        string password = parts[1];

                        if ((!string.IsNullOrWhiteSpace(username)) && (!string.IsNullOrWhiteSpace(password)))
                        {
                            return Users.Any(user => user.ValidateUser(username, password)) || Challenge(context);
                        }
                    }
                }
            }

            return Challenge(context);
        }

        private bool Challenge(HttpContext context)
        {
            context.Response.StatusCode = 401;
            context.Response.Headers.Append("WWW-Authenticate", "Basic realm=\"Hangfire Dashboard\"");

            context.Response.WriteAsync("Authentication is required.");

            return false;
        }
    }

Following is user credential class:

public class HangfireUserCredentials
    {
        public string Username { get; set; }
        public byte[] PasswordSha1Hash { get; set; }


        public string Password
        {
            set
            {
                using (var cryptoProvider = SHA1.Create())
                {
                    PasswordSha1Hash = cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(value));
                }
            }
        }

        public bool ValidateUser(string username, string password)
        {
            if (string.IsNullOrWhiteSpace(username))
                throw new ArgumentNullException("login");

            if (string.IsNullOrWhiteSpace(password))
                throw new ArgumentNullException("password");

            if (username == Username)
            {
                using (var cryptoProvider = SHA1.Create())
                {
                    byte[] passwordHash = cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(password));
                    return StructuralComparisons.StructuralEqualityComparer.Equals(passwordHash, PasswordSha1Hash);
                }
            }
            else
                return false;
        }
    }

And in the startup.cs add following code:

var options = new DashboardOptions
            {
                Authorization = new[] {
                    new DashboardAuthorization(new[]
                    {
                        new HangfireUserCredentials
                        {
                            Username = "user1",
                            Password = "#paassword"
                        }
                    })
                }
            };
            app.UseHangfireDashboard("/hangfire", options);
            app.UseHangfireServer();

 

 

Posted On: 16-May-2020 09:47
Rahul Maurya
Rahul M...
Teacher
1402 Points
236 Posts
         

Hangfire Dashboard exposes sensitive information about your background jobs, including method names and serialized arguments as well as gives you an opportunity to manage them by performing different actions – retry, delete, trigger, etc.
So it is really important to restrict access to the Dashboard. To make it secure by default, only local requests are allowed.
However you can change this by passing your own implementations of the IDashboardAuthorizationFilter interface, whose Authorize method is used to allow or prohibit a request.

We can follow instruction given on configuring-authorization

Also, provides Hangfire.Dashboard.Authorization package for basic access authentication-based (simple login-password auth) as well as User, role and claims -based authorization. See in Hangfire.Dashboard.Authorization

Install a NuGet Package:

Install-Package Hangfire.Dashboard.Authorization

So, we don’t want to reinvent the wheel. Just install this package and follow as:

Basic Authorization (simple login-password auth):

Add/modified following in Startup.cs in Configuration section:

var options = new DashboardOptions
{
    Authorization = new IDashboardAuthorizationFilter[]
    {
        new BasicAuthAuthorizationFilter(
            new BasicAuthAuthorizationFilterOptions
            {
                // Case sensitive login checking
                LoginCaseSensitive = true,
                // Users
                Users = new[]
                {
                    new BasicAuthAuthorizationUser
                    {
                        Login = "Administrator-1",
                        // Password as plain text, SHA1 will be used
                        PasswordClear = "testdashboard"
                    }
                }
            })
    }
};
app.UseHangfireDashboard("/hangfire", options);
app.UseHangfireServer();


Note: Place a call to the UseHangfireDashboard method after other authentication methods in your OWIN Startup class. Otherwise authentication may not work for you.

Posted On: 16-May-2020 11:49
 Log In to Chat