Git Product home page Git Product logo

stuntman's Introduction

Stuntman logo

"Sometimes you need a Stuntman before you send in real, unsuspecting users!"

Package Version
RimDev.Stuntman RimDev.Stuntman NuGet Version

Stuntman is a library for impersonating users during development leveraging .NET Claims Identity. Used primarily in web environments like ASP.NET MVC, ASP.NET Web Forms, and OWIN applications that serve HTML. This allows you to test different user scenarios that exist in your application with minimal friction. It also allows you to share those scenarios with other team members via source control.

Stuntman demo

Installation

Install the RimDev.Stuntman NuGet package.

PM> Install-Package RimDev.Stuntman

Usage

Startup / Middleware registration

Stuntman uses OWIN and is registered as middleware, and allows for programmatically preset user scenarios, in the form of claims identities. These presets can be utilized by you or other team members working on the same code base.

// OWIN Startup class
public class Startup
{
    public static readonly StuntmanOptions StuntmanOptions = new StuntmanOptions();

    public void Configuration(IAppBuilder app)
    {
        StuntmanOptions
            .AddUser(new StuntmanUser("user-1", "User 1")
                .AddClaim("given_name", "John")
                .AddClaim("family_name", "Doe"));

        // Optionally assign a user an access token.
        StuntmanOptions
            .AddUser(new StuntmanUser("user-2", "User 2")
                .SetAccessToken("123")
                .AddClaim("given_name", "Mary")
                .AddClaim("family_name", "Smith"));

        // You can also add users using HTTP/HTTPS or the file system!
        StuntmanOptions
            .AddUsersFromJson("https://example.com/web-test-users.json")
            .AddUsersFromJson(@"C:\local-test-users.json");

        // Optional alignment of user picker
        // Supported options are:
        // - StuntmanAlignment.Left (default)
        // - StuntmanAlignment.Center
        // - StuntmanAlignment.Right
        StuntmanOptions.SetUserPickerAlignment(StuntmanAlignment.Right);

        // Only show when debug is true in Web.config.
        if (System.Web.HttpContext.Current.IsDebuggingEnabled)
        {
            app.UseStuntman(StuntmanOptions);
        }
    }
}
// ASP.NET Core
public class Startup
{
    public static readonly StuntmanOptions StuntmanOptions = new StuntmanOptions();

    public Startup(IConfiguration configuration)
    {
        StuntmanOptions
            .AddUser(new StuntmanUser("user-1", "User 1")
                .AddClaim("given_name", "John")
                .AddClaim("family_name", "Doe"));

        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddStuntman(StuntmanOptions);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseStuntman(StuntmanOptions);
    }
}

View

Here's how to use Stuntman in a Razor view to show the user picker (assuming the application Startup class has StuntmanOptions that can be used).

@* Only show when debug is true in Web.config. *@
@if (System.Web.HttpContext.Current.IsDebuggingEnabled)
{
    @Html.Raw(YourApplicationNamespace.Startup.StuntmanOptions.UserPicker(User));
}

Bearer-token

Stuntman supports bearer-tokens based on a user's access-token (StuntmanUser.SetAccessToken). There is nothing special about the value and no additional encoding/decoding is necessary. Upon successful authentication, the value is added as a claim. Leveraging the previous Startup code, you could construct an HTTP-request to utilize User 2's access-token:

> curl -i -H "Authorization: Bearer 123" http://localhost:54917/secure
HTTP/1.1 200 OK

Basic format-checking is done on the value:

> curl -i -H "Authorization: Bearer not-real" http://localhost:54917/secure
HTTP/1.1 403 options provided does not include the requested 'not-real' user.
> curl -i -H "Authorization: Bearer abc 123" http://localhost:54917/secure
HTTP/1.1 400 Authorization header is not in correct format.

Remote users

Users can be populated from remote locations using one or more of the following:

  • From the file system
StuntmanOptions.AddUsersFromJson("C:\\path\\to\\users.json");
  • From a web url to a JSON file
StuntmanOptions.AddUsersFromJson("https://example.com/users.json");
  • From a web url to a Stuntman instance with a running server
//
// On the server
//
StuntmanOptions.EnableServer();

//
// On the client
//
StuntmanOptions.AddConfigurationFromServer("https://some-stuntman-enabled-app.example.com/");
// or, if you prefer to not throw an exception
// and have the users silently not added
// if the server is unavailable:
StuntmanOptions.TryAddConfigurationFromServer("https://some-stuntman-enabled-app.example.com/");

Example users JSON

Here's an example users JSON that can be consumed by StuntmanOptions.AddUsersFromJson(string pathOrUrl):

{
  "Users": [
    {
      "Id": "user-1",
      "Name": "User 1"
    },
    {
      "Id": "user-2",
      "Name": "User 2"
    }
  ]
}

Contributing

Have an idea? Let's talk about it in an issue!

Find a bug? Open an issue or submit a pull request!

License

MIT License

stuntman's People

Contributors

andrewlock avatar billbogaiv avatar dependabot[bot] avatar hougasian avatar jrusbatch avatar kendaleiv avatar khalidabuhakmeh avatar scottschwalm avatar snebjorn avatar tormentormaharaj avatar whoiskevinrich avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stuntman's Issues

Allow selective enabling of bearer-token and UI authentication

Currently, you get the platter when you might only want a side-item.

For internal projects at Ritter, we have a need to allow bearer-token auth, but disallow UI auth (and vice-versa) on our QA sites.

I propose using the StuntmanOptions-instance passed to UseStuntman to selectively enable bearer-token and UI authentication as two separate properties on the options instance (this could be combined as one property using &, but it seems overkill for only two possible values).

Impersonating Google bearer token

I am using Google authentication for user login in my app.
Would it be possible to use stuntman to impersonate users, and if so, how?
Thanx!

Support Stunts / Actions

Stuntman is currently focused on Authentication scenarios, but I believe it can do more.

I would like to propose the idea of a Stunt:

A stunt is a code block that can be executed at will from the UI that may or may not require input, and additionally may or may not return a result to the developer. Stunts can only be performed during development.

Code (pseudo)

Here is what implementing a stunt may look like in code.

public class ResetPasswordVerificationKeyStunt : Stunt {
     // set by StuntCoordinator
     public string UserId { get; set; }

     public override string Perform(StuntContext context) {
            var container = context["Container"] as Container;
            var db = container.Resolve<UserRepository>();

            var token = Guid.NewGuid().ToString("D");
            var user = db.GetUser(UserId);

            user.VerificationKey = token;
            db.Save(user);

            return $"token : {token}";
     }
} 

Then you would register this action with the StuntmanOptions

StuntmanOptions
   .AddStunt<ResetPasswordVerificationKeyStunt>();

UI

balsamiq_mockups_for_desktop_-___new_mockup

Unify projects to support ASP.NET and ASP.NET Core 2.0

Note: This issue is a breaking change and most likely a major version bump. When this is being worked on, no other work should be happening as it will be ignored.


Exploring migrating Stuntman to VS 2017 and I have a working build of the core solution and the tests. Here is what we need to do:

  1. Reduce the Core projects to one project called RimDev.Stuntman and modify namespaces accordingly to match
  2. Reduce all test projects to one
  3. Use compiler directives to target NETSTANDARD1_4 and NET451
  4. Upgrade all old versions of csproj to the latest
  5. Samples need to be migrated too

Current Csproj for RimDev.Stuntman

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <Copyright>Copyright 2017 Ritter Insurance Marketing</Copyright>
    <VersionPrefix>1.7.0</VersionPrefix>
    <Authors>Ritter Insurance Marketing</Authors>
    <TargetFrameworks>net451;netstandard1.4</TargetFrameworks>
    <AssemblyName>RimDev.Stuntman</AssemblyName>
    <PackageId>RimDev.Stuntman</PackageId>
    <PackageTags>rimdev;stuntman;aspnet;identity;impersonation</PackageTags>
    <PackageIconUrl>https://raw.githubusercontent.com/ritterim/stuntman/master/stuntman-icon-128.png</PackageIconUrl>
    <PackageProjectUrl>https://github.com/ritterim/stuntman</PackageProjectUrl>
    <PackageLicenseUrl>https://raw.githubusercontent.com/ritterim/stuntman/master/LICENSE</PackageLicenseUrl>
    <RepositoryType>git</RepositoryType>
    <RepositoryUrl>https://github.com/ritterim/stuntman.git</RepositoryUrl>
    <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="..\..\common\SolutionInfo.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
    <EmbeddedResource Include="assets\stuntman.css;assets\stuntman-logo.png" Exclude="bin\**;obj\**;**\*.xproj;packages\**;@(EmbeddedResource)" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
  </ItemGroup>

  <ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
    <Reference Include="System.IdentityModel" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Runtime" />
    <Reference Include="System" />
    <Reference Include="Microsoft.CSharp" />
    <PackageReference Include="Microsoft.Owin" Version="3.0.1" />
    <PackageReference Include="Microsoft.Owin.Security" Version="3.0.1" />
    <PackageReference Include="Microsoft.Owin.Security.Cookies" Version="3.0.1" />
    <PackageReference Include="Microsoft.Owin.Security.OAuth" Version="3.0.1" />
    <PackageReference Include="Owin" Version="1.0" />
  </ItemGroup>

  <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.4' ">
    <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="1.0.2" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.0.2" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="1.0.2" />
    <PackageReference Include="System.Security.Claims" Version="4.0.1" />
    <PackageReference Include="System.IO.FileSystem" Version="4.0.1" />
    <PackageReference Include="System.Net.Http" Version="4.1.1" />
    <PackageReference Include="System.Runtime.Extensions" Version="4.1.0" />
  </ItemGroup>

</Project>

Only activate stuntman after "real" authentication.

Hi,

I have stuntman installed and works great for dev but i would also like to use it in our demo/test environment on the web (open for basically anyone).

Issue now is that anyone can just pick a user and get in but i would like the original owin authentication to pop up first and after that be able to use stuntman to quickly demo/test.

Thanks

Franc

Allow bearer-token pass-through instead of outright rejection

Somewhat related to #133.

Background info.

For internal projects at Ritter, we want to allow a better dev. experience when working with apps. which talk to each other. When working locally, the communication normally flows using the other app's QA site. Identity Server is our auth provider when not running locally. To get our scenario to work, we need to augment the dev. app's auth configuration to use IdSrv and remember not to commit the changes.

Proposed change

Currently, Stuntman rejects the request if a bearer token is invalid. While this can continue to be the default behavior, an additional option will allow other auth providers a chance to validate the token. This now allows a scenario where we can have our dev. apps using Stuntman to pass a token to a QA-running app., let Stuntman on the latter get first crack at validating the token, and only passing to IdSrv if it cannot successfully validate.

A short test-session revealed that by removing the explicit 403 status code, the OWIN pipeline continued. The 403 seems to have special meaning, but I could not find where this actually comes into play and stops other middleware from executing.

Update samples

I noticed some of your samples aren't updated/correctly setup. You should update them to at least cover minimum supported target versions, which are .net core 2.1 and .net framework 4.6.1

This is how it looks today and some suggestions:

samples/UsageSample.AspNetCore

  • targets .net core 2.1

samples/UsageSample.BearerTokenTester

  • targets .net 4.5, but should be updated for .net 4.6.1

samples/ServerTester

  • targets .net 4.6.1, but is not correctly configured:
  • App.config
    change sku to .NETFramework,Version=v4.6.1

samples/UsageSample

  • targets .net 4.6.1, but is not correctly configured:
  • Web.config
    change both targetFramework to 4.6.1

samples/UsageSampleMvc.AspNetCore

  • targets .net core 2.2

Runtime specification of custom user

Allowing runtime specification of a StuntmanUser might be handy for some scenarios (QA environments), where you want to impersonate a specific user not necessarily known at development time.

Or, is this something we want to avoid for any number of reasons? In terms of a QA environment, would this be bad idea in terms of QA differing too much from production? Although, that might be something for users of Stuntman to determine on their own on a case-by-case basis.

Implementation thoughts

Perhaps the UI could have a Custom option added to the user picker and choose-a-user screen, with the necessary fields appearing in some manner after clicking the Custom option.

@hougasian might have some ideas.

Stuntman vNext

  • Inline editing of users
    • Ability to manage user-claims
  • Revisit bearer token logic
    • See whether we can update logic to make it more streamlined without breaking existing behaviors
  • Reduce cookie bloat
    • Hydrate user in middleware during runtime instead of pushing data into cookie
  • Allow turning Stuntman on/off during runtime
    • Current behavior requires logic applied during compliation
    • Ref. #169
  • Documentation
  • Delegating handler for HttpClient
    • track HttpClient calls and provide responses to alleviate the need for actual HTTP traffic
  • API
    • will be used by UI instead of embedding directly into HTML
  • Avatar

Colorized helmet indicators

@hougasian had an idea for having differing helmet colors for users accomplished with a custom font.

We'd probably want to incorporate the colors into the list of items as well (perhaps a helmet in front of each item, but lower opacity, with a currently in-use one with full opacity?).

Install dependent nugets when installing the Stuntman nuget package.

I tried to install Stuntman in an application and got a YSOD because it couldn't find assembly Microsoft.Owin.Security.OAuth version 3.0.1. I had to install that nuget package manually.

I think the stuntman nuget package should install all required/dependent nuget packages upon installation.

Skip stuntman

Add option on initial selection to skip/turn off stuntman for session

Create a Stuntman Logo

It would be awesome to create a logo that works both in the Nuget.org gallery, on the widget as a badge, and on the login page as a title. Also it would be great to put into the readme file.

Automatically inject UserPicker into view

It would be awesome if the UserPicker would be injected into the view without the need for

@using RimDev.Stuntman.Core
@inject StuntmanOptions StuntmanOptions
<!DOCTYPE html>
<html>
...
    <environment names="Development">
        @Html.Raw(StuntmanOptions.UserPicker(User))
    </environment>
</body>
</html>

BrowserLink works that way.
All you have to do is app.UseBrowserLink(); and this is injected into the view.

    <!-- Visual Studio Browser Link -->
    <script type="application/json" id="__browserLink_initializationData">
        {"requestId":"a717d5a07c1741949a7cefd6fa2bad08","requestMappingFromServer":false}
    </script>
    <script type="text/javascript" src="http://localhost:54139/b6e36e429d034f578ebccd6a79bf19bf/browserLink" async="async"></script>
    <!-- End Browser Link -->

source

Adding claims

I'm new to claims in general, but believe in TDD. I was wondering how I can give a StuntmanUser a claim for multiple roles? Is there a list of supported claims?

Allow For User Groups / Categorization

While not always necessary, the stable of test users may grow in a way that makes the UI unwieldy and hard to navigate.

For the Stuntman vNext, it might make sense to categorize users by some mechanism.

  • A single Category field on a user.
  • Tags on a user with UI filtering

Thoughts and opinions are welcome.

Internally generate user-Id

Manually assigning a user-Id is unnecessary and should be handled automatically when a user is added to the collection.

UserPicker doesn't set current user in UseSampleMvc.AspNetCore

The sample doesn't set the current user. The user picker always displays the anonymous user as the selected/picked user.

After some investigation I identified the problem. The user picker is determines the current user based on the current principal identity name. In the sample the added users don't have a name. I fixed this in a local branch and would love to provide you with a PR.

Wouldn't it be better to add a claim for the name of the StuntmanUser within the constructor? The DefaultNameClaimType is name by default anyway.

Add .NETStandard 2.0 support

The latest version 1.7.1 supports .NETStandard 1.4. It would be great if you can support for .NETStandard 2.0. Thank you!

Improve code used on Razor views

  • Simplify the code necessary for adding the user picker to a view
    • Avoid taking an ASP.NET MVC dependency
    • Ideally support ASP.NET vnext
  • Update all sample code (including gh-pages branch)

Unified common users

Storing a set of users in a centralized common place between applications could be useful for multi-application scenarios where you want to share the same set of users between applications.

Use fewer code lines for UserPicker

Since the full contents of the UserPicker is added directly into the HTML of the page, it might be nice if we outputted fewer code lines, even if those lines are very wide.

A user viewing the page source is probably not interested in the stuntman stuff. This may make it easier to glance past it.

Set cookie domain for .AspNet.StuntmanAuthentication

Hi,

I have two mvc projects side by side and would like to use stuntman across both.

.AspNet.StuntmanAuthentication now has demo1.xyz.com as the domain on one site and demo2.xyz.com on the other site.

With app.UseCookieAuthentication(new CookieAuthenticationOptions { CookieDomain = ".xyz.com" } ) i can share the cookie for owin but is something similar possible with Stuntman?

Thanks.

Make StuntmanUser more fluent

The current implementation of creating a stuntman user looks like this.

new StuntmanUser
{
    Id = "user-2",
    Name = "User 2",
    Claims = new[]
    {
        new Claim("given_name", "Jane"),
        new Claim("family_name", "Doe")
    }
}

I'd like to be able to declare a user like this.

new StuntmanUser("user-2", "User 2")
  .AddClaim("given_name", "Jane")
  .AddClaim("family_name", "Doe");

Doesn't seem to work with .NET Core 3.1

I tried to include this in a project based on dotnet core 3.1
It doesn't throw any errors, but I am not able to select stuntman users either.
It remains in "Anonymous".

I have attached a sample project which reproduces the issue.

Please let me know if I can do anything more to resolve this.
If someone pointed me in the right direction I'd gladly try to solve this myself and submit a PR.

StuntmanTest.zip

Compilation Error

Following the instructions in the readme, I've added the following to my Startup.cs

    public class Startup
    {
        public readonly StuntmanOptions StuntmanOptions = new StuntmanOptions();

        public void Configuration(IAppBuilder app)
        {

            StuntmanOptions.AddUser(new StuntmanUser("ajoe")
                    .AddClaim("given_name", "Average")
                    .AddClaim("family_name", "Joe"));

            StuntmanOptions.SetUserPickerAlignment(StuntmanAlignment.Right);

            if (System.Web.HttpContext.Current.IsDebuggingEnabled)
            {
                app.UseStuntman(StuntmanOptions);
            }
        }
    }

and the following to my view:

@if (HttpContext.Current.IsDebuggingEnabled)
{
    @Html.Raw(Startup.StuntmanOptions.UserPicker(User))
}

However, I'm seeing "an object reference is required for the non-static field, method, or property 'Startup.StuntmanOptions'. Am I missing a step?

Api in subfolder not working

๐Ÿ› Bug Report

If the dotnet core MVC api is in an subfolder then stuntman endpoints not available.

To Reproduce

Steps to reproduce the behavior:

  • Setup dotnet core 3.1 project.
  • In startup
    `var options = new StuntmanOptions("/TEST");
    services.AddStuntman(StuntmanOptions);

app.UsePathBase("/TEST");
app.UseStuntman(StuntmanOptions);

`

Expected behavior

Under http://localhost:44349/TEST/sign-in the sign in page is available.

Screenshots and/or request snippets

grafik

Update Samples To Be "Wiz Bang!"

The sample project currently startup and are very blech. Spending some time on showing the features implemented inside of Stuntman and how to implement them would go a long way.\

This should be the feeling right after someone hits F5.

Support multi-application scenarios

Today, Stuntman can load users from paths and urls by virtue of AddUsersFromJson(string).

However, we want to support the notion of a client/server relationship, where the client requests the users that are configured in the server.

  • The server will need to expose the users via a special endpoint
  • The client can request these users to add to the list of users, or make a request for the access token or other information for a particular user.
    • We may want to support both mandatory and optional scenarios in terms of the server responding successfully.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.