Skip to content

Commit f7efbe7

Browse files
Merge branch 'develop'
# Conflicts: # README.md
2 parents a8ceed1 + 6758778 commit f7efbe7

26 files changed

+470
-263
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,4 +249,5 @@ Cached/
249249
# Custom
250250
build/_nuget
251251
src/Our.Umbraco.AuthU.TestHarness
252+
src/Our.Umbraco.AuthU.Web
252253
src/Our.Umbraco.AuthU.Matt.*

LICENSE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright © 2017 Matt Brialsford, Outfield Digital Ltd
3+
Copyright © 2017 Matt Brailsford, Outfield Digital Ltd
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy of
66
this software and associated documentation files (the "Software"), to deal in

README.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ For the most basic OAuth implementation, the following minimal configuration is
3434
This will create an endpoint at the path `/oauth/token`, authenticating requests against the Umbraco members store, issuing access tokens with a lifespan of 20 minutes.
3535

3636
### Advanced Configuration
37-
For a more advanced OAuth implementation, the following conifguration shows all the supported options.
37+
For a more advanced OAuth implementation, the following configuration shows all the supported options.
3838
````csharp
3939
OAuth.ConfigureEndpoint("realm", "/oauth/token", new OAuthOptions {
4040
UserService = new UmbracoMembersOAuthUserService(),
@@ -52,7 +52,7 @@ This will create an endpoint the same as the basic configuration with added supp
5252
### Configuration Options
5353
* __Realm : string__
5454
_[optional, default:"default"]_
55-
A uniqie alias for the configuration, allowing you to configure multiple endpoints.
55+
A unique alias for the configuration, allowing you to configure multiple endpoints.
5656
* __Path : string__
5757
_[optional, default:"/oauth/token"]_
5858
The path of the endpoint (__IMPORTANT!__ Be sure to add the base of the path to the `umbracoReservedPaths` app setting, ie `~/oauth/`)
@@ -61,7 +61,7 @@ This will create an endpoint the same as the basic configuration with added supp
6161
The service from which to validate authentication requests against. Out of the box AuthU comes with 2 implementations, `UmbracoMembersOAuthUserService` and `UmbracoUsersOAuthUserService` which authenticate against the Umbraco members and users store respectively. Custom sources can be configured by implementing the `IOAuthUserService` interface yourself.
6262
* __SymmetricKey : string__
6363
_[required]_
64-
A symetric key used to sign the generated access tokens. Must be a string, 32 characters long, BASE64 encoded.
64+
A symmetric key used to sign the generated access tokens. Must be a string, 32 characters long, BASE64 encoded.
6565
* __AccessTokenLifeTime : int__
6666
_[optional, default:20]_
6767
Sets the lifespan, in minutes, of an access token before re-authentication is required. Should be short lived.
@@ -76,7 +76,7 @@ This will create an endpoint the same as the basic configuration with added supp
7676
Sets the lifespan, in minutes, of a refresh token before it can no longer be used. Can be long lived. If a client store is configured, this will get overridden by the client settings.
7777
* __AllowedOrigin : string__
7878
_[optional, default:"*"]_
79-
Sets the allowed domain from which authentication requests can be made. If developing a web application, it is strongly recommended to set this to the domain from which your app is hosted at to prevent access from unwanted sources. If developing a mobile app, it can be set to wildcard "*" which will allow any source to access it, however it is strongly recommended you use a client store which requires a secret key to be passed. If a client store is configured, this will get overridden by the client settings.
79+
Sets the allowed domain from which authentication requests can be made. If developing a web application, it is strongly recommended to set this to the domain from which your app is hosted at to prevent access from unwanted sources. If developing a mobile app, it can be set to wildcard "*" which will allow any source to access it, however it is strongly recommended you use a client store which requires a secret key to be passed. If a client store is configured, this will get overridden by the client settings. If you are managing CORS headers yourself and you don't want AuthU to set the allowed origins header for you, you will need to explicitly set this to `null`.
8080
* __AllowInsecureHttp : bool__
8181
_[optional, default:false]_
8282
Sets whether the api should allow requests over insecure HTTP. You'll probably want to set this to `true` during development, but it is strongly advised to disable this in the live environment.
@@ -89,15 +89,16 @@ With an endpoint configured, initial authentication can be performed by sending
8989
* __password__ = The users password
9090
* __client_id__ = A valid client id (Only required if a client store is configured)
9191
* __client_secret__ = A valid client secret (Only required if a client store is configured, and the client is "secure")
92+
* __device_id__ = An optional device id to associate the token with, allowing login from multiple devices
9293

9394
Example (with client store and refresh token stores configured):
9495

9596
Request URL:
96-
POST https://mydomain.com/oauth/token
97+
POST https://mydomain.com/oauth/token
9798
Request Headers:
9899
Content-Type: application/x-www-form-urlencoded
99100
Request POST Body:
100-
grant_type=password&username=joebloggs&password=password1234&client_id=myclient&client_secret=myclientsecret
101+
grant_type=password&username=joebloggs&password=password1234&client_id=myclient&client_secret=myclientsecret&device_id=edfb6f01-2342-47f8-a5ee-a520969539d0
101102
Response:
102103
{
103104
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1laWQiOiIxMDgxIiwidW5pcXVlX25hbWUiOiJtZW1iZXIiLCJyb2xlIjoiTWVtYmVyIiwicmVhbG0iOiJkZWZhdWx0IiwiZXhwIjoxNDg3NDk2NzM3LCJuYmYiOjE0ODc0OTU1Mzd9.9uiIxrPggvH5nyLbH4UKIL52V6l5mpOyJ26J12FkXvI",
@@ -111,15 +112,16 @@ A subsequent refresh token authentication request can be performed by sending a
111112
* __refresh_token__ = The refresh token returned from the original authentication request
112113
* __client_id__ = A valid client id (Only required if a client store is configured)
113114
* __client_secret__ = A valid client secret (Only required if a client store is configured, and the client is "secure")
115+
* __device_id__ = An optional device id to associate the token with, allowing login from multiple devices
114116

115117
Example (with client store and refresh token stores configured):
116118

117119
Request URL:
118-
POST https://mydomain.com/oauth/token
120+
POST https://mydomain.com/oauth/token
119121
Request Headers:
120122
Content-Type: application/x-www-form-urlencoded
121123
Request POST Body:
122-
grant_type=refresh_token&refresh_token=b3cc9c66b86340c5b743f2a7cec9d2f1&client_id=myclient&client_secret=myclientsecret
124+
grant_type=refresh_token&refresh_token=b3cc9c66b86340c5b743f2a7cec9d2f1&client_id=myclient&client_secret=myclientsecret&device_id=edfb6f01-2342-47f8-a5ee-a520969539d0
123125
Response:
124126
{
125127
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1laWQiOiIxMDgxIiwidW5pcXVlX25hbWUiOiJtZW1iZXIiLCJyb2xlIjoiTWVtYmVyIiwicmVhbG0iOiJkZWZhdWx0IiwiZXhwIjoxNDg3NDk2NzM3LCJuYmYiOjE0ODc0OTU1Mzd9.9uiIxrPggvH5nyLbH4UKIL52V6l5mpOyJ26J12FkXvI",
@@ -152,7 +154,7 @@ To access a protected action, an `Authorization` header should be added to the r
152154
Example:
153155

154156
Request URL:
155-
POST https://mydomain.com/umbraco/api/myapi/helloworld
157+
POST https://mydomain.com/umbraco/api/myapi/helloworld
156158
Request Headers:
157159
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1laWQiOiIxMDgxIiwidW5pcXVlX25hbWUiOiJtZW1iZXIiLCJyb2xlIjoiTWVtYmVyIiwicmVhbG0iOiJkZWZhdWx0IiwiZXhwIjoxNDg3NDk2NzM3LCJuYmYiOjE0ODc0OTU1Mzd9.9uiIxrPggvH5nyLbH4UKIL52V6l5mpOyJ26J12FkXvI
158160
Response:
@@ -168,6 +170,6 @@ Anyone and everyone is welcome to contribute. Please take a moment to review the
168170

169171
## License
170172

171-
Copyright © 2018 Matt Brialsford, Outfield Digital Ltd
173+
Copyright © 2018 Matt Brailsford, Outfield Digital Ltd
172174

173175
Licensed under the [MIT License](LICENSE.md)

appveyor.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
os: Visual Studio 2015
1+
image: Visual Studio 2017
22

33
# version format
4-
version: 1.0.2.{build}
4+
version: 1.0.3.{build}
55

66
# UMBRACO_PACKAGE_PRERELEASE_SUFFIX if a rtm release build this should be blank, otherwise if empty will default to alpha
77
# example UMBRACO_PACKAGE_PRERELEASE_SUFFIX=beta

build-appveyor.cmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ ECHO APPVEYOR_BUILD_NUMBER : %APPVEYOR_BUILD_NUMBER%
44
ECHO APPVEYOR_BUILD_VERSION : %APPVEYOR_BUILD_VERSION%
55

66
CALL src\.nuget\NuGet.exe restore src\Our.Umbraco.AuthU.sln
7-
CALL "%programfiles(x86)%\MSBuild\14.0\Bin\amd64\MsBuild.exe" build\package.proj
7+
CALL "%programfiles(x86)%\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\amd64\MsBuild.exe" build\package.proj

build/package.nuspec

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
<language></language>
1717
<tags></tags>
1818
<dependencies>
19-
<dependency id="UmbracoCms.Core" version="7.5.0" />
20-
<dependency id="System.IdentityModel.Tokens.Jwt" version="4.0.4.402070948" />
19+
<dependency id="System.IdentityModel.Tokens.Jwt" version="5.2.4" />
2120
</dependencies>
2221
</metadata>
2322
<files />
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Umbraco.Core;
2+
using Umbraco.Core.Logging;
3+
using Umbraco.Core.Persistence;
4+
using Umbraco.Core.Persistence.Migrations;
5+
using Umbraco.Core.Persistence.SqlSyntax;
6+
7+
namespace Our.Umbraco.AuthU.Data.Migrations
8+
{
9+
internal abstract class BaseMigration : MigrationBase
10+
{
11+
protected Database Database
12+
{
13+
get
14+
{
15+
return ApplicationContext.Current.DatabaseContext.Database;
16+
}
17+
}
18+
19+
protected DatabaseSchemaHelper SchemaHelper
20+
{
21+
get
22+
{
23+
return new DatabaseSchemaHelper(Database, Logger, SqlSyntax);
24+
}
25+
}
26+
27+
protected BaseMigration(ISqlSyntaxProvider sqlSyntax, ILogger logger)
28+
: base(sqlSyntax, logger)
29+
{ }
30+
}
31+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Semver;
2+
using System;
3+
using System.Linq;
4+
using Umbraco.Core;
5+
using Umbraco.Core.Logging;
6+
using Umbraco.Core.Persistence.Migrations;
7+
8+
namespace Our.Umbraco.AuthU.Data.Migrations
9+
{
10+
internal class MigrationsRunner
11+
{
12+
public static void RunMigrations(string version, string productName)
13+
{
14+
var currentVersion = new SemVersion(0, 0, 0);
15+
16+
var migrations = ApplicationContext.Current.Services.MigrationEntryService.GetAll(productName);
17+
var latestMigration = migrations.OrderByDescending(x => x.Version).FirstOrDefault();
18+
if (latestMigration != null)
19+
currentVersion = latestMigration.Version;
20+
21+
var targetVersion = SemVersion.Parse(version);
22+
if (targetVersion == currentVersion)
23+
return;
24+
25+
var migrationsRunner = new MigrationRunner(
26+
ApplicationContext.Current.Services.MigrationEntryService,
27+
ApplicationContext.Current.ProfilingLogger.Logger,
28+
currentVersion,
29+
targetVersion,
30+
productName);
31+
32+
try
33+
{
34+
migrationsRunner.Execute(ApplicationContext.Current.DatabaseContext.Database);
35+
}
36+
catch (Exception e)
37+
{
38+
LogHelper.Error<MigrationsRunner>($"Error running {productName} migration", e);
39+
}
40+
}
41+
}
42+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Our.Umbraco.AuthU.Models;
2+
using Umbraco.Core.Logging;
3+
using Umbraco.Core.Persistence.Migrations;
4+
using Umbraco.Core.Persistence.SqlSyntax;
5+
6+
namespace Our.Umbraco.AuthU.Data.Migrations.UmbracoDbOAuthClientStore
7+
{
8+
[Migration("1.0.0", 2, "AuthU_UmbracoDbOAuthClientStore")]
9+
internal class CreateDemoClient : BaseMigration
10+
{
11+
public CreateDemoClient(ISqlSyntaxProvider sqlSyntax, ILogger logger)
12+
: base(sqlSyntax, logger)
13+
{ }
14+
15+
public override void Up()
16+
{
17+
var existing = Database.SingleOrDefault<OAuthClient>($"SELECT * FROM [OAuthClient] WHERE [ClientId] = @0", "DemoClient");
18+
if (existing == null)
19+
{
20+
Database.Save(new OAuthClient
21+
{
22+
ClientId = "DemoClient",
23+
Name = "Demo Client",
24+
Secret = "demo",
25+
SecurityLevel = SecurityLevel.Insecure,
26+
RefreshTokenLifeTime = 14400,
27+
AllowedOrigin = "*"
28+
});
29+
}
30+
}
31+
32+
public override void Down()
33+
{
34+
Database.Execute("DELETE [OAuthClient] WHERE [ClientId] = @0", "DemoClient");
35+
}
36+
}
37+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using Our.Umbraco.AuthU.Models;
2+
using Umbraco.Core.Logging;
3+
using Umbraco.Core.Persistence.Migrations;
4+
using Umbraco.Core.Persistence.SqlSyntax;
5+
6+
namespace Our.Umbraco.AuthU.Data.Migrations.UmbracoDbOAuthClientStore
7+
{
8+
[Migration("1.0.0", 1, Data.UmbracoDbOAuthClientStore.SubProductName)]
9+
internal class CreateTable : BaseMigration
10+
{
11+
public CreateTable(ISqlSyntaxProvider sqlSyntax, ILogger logger)
12+
: base(sqlSyntax, logger)
13+
{ }
14+
15+
public override void Up()
16+
{
17+
SchemaHelper.CreateTable<OAuthClient>(false);
18+
}
19+
20+
public override void Down()
21+
{
22+
SchemaHelper.DropTable<OAuthClient>();
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)