mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
Added customization of scopes and grant type for clients
This commit is contained in:
parent
d47b5e5785
commit
94be2cf236
@ -542,19 +542,15 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
ClientName = model.Name,
|
ClientName = model.Name,
|
||||||
ClientUri = model.HomepageUrl,
|
ClientUri = model.HomepageUrl,
|
||||||
LogoUri = model.LogoUrl,
|
LogoUri = model.LogoUrl,
|
||||||
AllowedGrantTypes = new List<string>()
|
|
||||||
{
|
AllowedGrantTypes = model.AllowedGrants,
|
||||||
GrantType.AuthorizationCode,
|
AllowedScopes = model.AllowedScopes,
|
||||||
GrantType.ClientCredentials
|
|
||||||
},
|
|
||||||
|
|
||||||
ClientSecrets =
|
ClientSecrets =
|
||||||
{
|
{
|
||||||
new IdentityServer4.Models.Secret(clientSecret.Sha256())
|
new IdentityServer4.Models.Secret(clientSecret.Sha256())
|
||||||
},
|
},
|
||||||
|
|
||||||
RequireConsent = true,
|
|
||||||
|
|
||||||
RedirectUris =
|
RedirectUris =
|
||||||
{
|
{
|
||||||
model.CallbackUrl
|
model.CallbackUrl
|
||||||
@ -565,8 +561,7 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
origin
|
origin
|
||||||
},
|
},
|
||||||
|
|
||||||
AllowedScopes = model.AllowedScopes,
|
RequireConsent = true,
|
||||||
|
|
||||||
AllowOfflineAccess = true
|
AllowOfflineAccess = true
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -617,6 +612,36 @@ namespace Teknik.IdentityServer.Controllers
|
|||||||
newOrigin.Origin = origin;
|
newOrigin.Origin = origin;
|
||||||
configContext.Add(newUri);
|
configContext.Add(newUri);
|
||||||
|
|
||||||
|
// Update their allowed grants
|
||||||
|
var curGrants = configContext.Set<ClientGrantType>().Where(c => c.ClientId == foundClient.Id).ToList();
|
||||||
|
if (curGrants != null)
|
||||||
|
{
|
||||||
|
configContext.RemoveRange(curGrants);
|
||||||
|
}
|
||||||
|
foreach (var grantType in model.AllowedGrants)
|
||||||
|
{
|
||||||
|
var newGrant = new ClientGrantType();
|
||||||
|
newGrant.Client = foundClient;
|
||||||
|
newGrant.ClientId = foundClient.Id;
|
||||||
|
newGrant.GrantType = grantType;
|
||||||
|
configContext.Add(newGrant);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update their allowed scopes
|
||||||
|
var curScopes = configContext.Set<ClientScope>().Where(c => c.ClientId == foundClient.Id).ToList();
|
||||||
|
if (curScopes != null)
|
||||||
|
{
|
||||||
|
configContext.RemoveRange(curScopes);
|
||||||
|
}
|
||||||
|
foreach (var scope in model.AllowedScopes)
|
||||||
|
{
|
||||||
|
var newScope = new ClientScope();
|
||||||
|
newScope.Client = foundClient;
|
||||||
|
newScope.ClientId = foundClient.Id;
|
||||||
|
newScope.Scope = scope;
|
||||||
|
configContext.Add(newScope);
|
||||||
|
}
|
||||||
|
|
||||||
// Save all the changed
|
// Save all the changed
|
||||||
configContext.SaveChanges();
|
configContext.SaveChanges();
|
||||||
|
|
||||||
|
@ -13,5 +13,6 @@ namespace Teknik.IdentityServer.Models.Manage
|
|||||||
public string LogoUrl { get; set; }
|
public string LogoUrl { get; set; }
|
||||||
public string CallbackUrl { get; set; }
|
public string CallbackUrl { get; set; }
|
||||||
public ICollection<string> AllowedScopes { get; set; }
|
public ICollection<string> AllowedScopes { get; set; }
|
||||||
|
public ICollection<string> AllowedGrants { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,5 +13,7 @@ namespace Teknik.IdentityServer.Models.Manage
|
|||||||
public string HomepageUrl { get; set; }
|
public string HomepageUrl { get; set; }
|
||||||
public string LogoUrl { get; set; }
|
public string LogoUrl { get; set; }
|
||||||
public string CallbackUrl { get; set; }
|
public string CallbackUrl { get; set; }
|
||||||
|
public ICollection<string> AllowedScopes { get; set; }
|
||||||
|
public ICollection<string> AllowedGrants { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
},
|
},
|
||||||
"applicationUrl": "https://localhost:6002/"
|
"applicationUrl": "https://localhost:9002/"
|
||||||
},
|
},
|
||||||
"IdentityServer - Prod": {
|
"IdentityServer - Prod": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
@ -29,7 +29,7 @@
|
|||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Production"
|
"ASPNETCORE_ENVIRONMENT": "Production"
|
||||||
},
|
},
|
||||||
"applicationUrl": "https://localhost:6002/"
|
"applicationUrl": "https://localhost:9002/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,7 +18,6 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="TwoFactorCode"></label>
|
<label asp-for="TwoFactorCode"></label>
|
||||||
<input asp-for="TwoFactorCode" class="form-control" autocomplete="off" />
|
<input asp-for="TwoFactorCode" class="form-control" autocomplete="off" />
|
||||||
<span asp-validation-for="TwoFactorCode" class="text-danger"></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="abc-checkbox">
|
<div class="abc-checkbox">
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="RecoveryCode"></label>
|
<label asp-for="RecoveryCode"></label>
|
||||||
<input asp-for="RecoveryCode" class="form-control" autocomplete="off" />
|
<input asp-for="RecoveryCode" class="form-control" autocomplete="off" />
|
||||||
<span asp-validation-for="RecoveryCode" class="text-danger"></span>
|
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-default pull-right">Log in</button>
|
<button type="submit" class="btn btn-default pull-right">Log in</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -437,7 +437,8 @@ namespace Teknik.Areas.Users.Controllers
|
|||||||
HomepageUrl = client.ClientUri,
|
HomepageUrl = client.ClientUri,
|
||||||
LogoUrl = client.LogoUri,
|
LogoUrl = client.LogoUri,
|
||||||
CallbackUrl = string.Join(',', client.RedirectUris),
|
CallbackUrl = string.Join(',', client.RedirectUris),
|
||||||
AllowedScopes = client.AllowedScopes
|
AllowedScopes = client.AllowedScopes,
|
||||||
|
GrantType = IdentityHelper.GrantsToGrantType(client.AllowedGrantTypes.ToArray())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1239,7 +1240,7 @@ namespace Teknik.Areas.Users.Controllers
|
|||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[ValidateAntiForgeryToken]
|
[ValidateAntiForgeryToken]
|
||||||
public async Task<IActionResult> CreateClient(string name, string homepageUrl, string logoUrl, string callbackUrl, [FromServices] ICompositeViewEngine viewEngine)
|
public async Task<IActionResult> CreateClient(string name, string homepageUrl, string logoUrl, string callbackUrl, IdentityClientGrant grantType, string scopes, [FromServices] ICompositeViewEngine viewEngine)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -1255,7 +1256,15 @@ namespace Teknik.Areas.Users.Controllers
|
|||||||
return Json(new { error = "Invalid logo URL" });
|
return Json(new { error = "Invalid logo URL" });
|
||||||
|
|
||||||
// Validate the code with the identity server
|
// Validate the code with the identity server
|
||||||
var result = await IdentityHelper.CreateClient(_config, User.Identity.Name, name, homepageUrl, logoUrl, callbackUrl, "openid", "role", "account-info", "security-info", "teknik-api.read", "teknik-api.write");
|
var result = await IdentityHelper.CreateClient(
|
||||||
|
_config,
|
||||||
|
User.Identity.Name,
|
||||||
|
name,
|
||||||
|
homepageUrl,
|
||||||
|
logoUrl,
|
||||||
|
callbackUrl,
|
||||||
|
IdentityHelper.GrantTypeToGrants(grantType),
|
||||||
|
scopes.Split(','));
|
||||||
|
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
@ -1267,6 +1276,8 @@ namespace Teknik.Areas.Users.Controllers
|
|||||||
model.HomepageUrl = homepageUrl;
|
model.HomepageUrl = homepageUrl;
|
||||||
model.LogoUrl = logoUrl;
|
model.LogoUrl = logoUrl;
|
||||||
model.CallbackUrl = callbackUrl;
|
model.CallbackUrl = callbackUrl;
|
||||||
|
model.GrantType = grantType;
|
||||||
|
model.AllowedScopes = scopes.Split(',');
|
||||||
|
|
||||||
string renderedView = await RenderPartialViewToString(viewEngine, "~/Areas/User/Views/User/Settings/ClientView.cshtml", model);
|
string renderedView = await RenderPartialViewToString(viewEngine, "~/Areas/User/Views/User/Settings/ClientView.cshtml", model);
|
||||||
|
|
||||||
@ -1287,14 +1298,15 @@ namespace Teknik.Areas.Users.Controllers
|
|||||||
Client foundClient = await IdentityHelper.GetClient(_config, User.Identity.Name, clientId);
|
Client foundClient = await IdentityHelper.GetClient(_config, User.Identity.Name, clientId);
|
||||||
if (foundClient != null)
|
if (foundClient != null)
|
||||||
{
|
{
|
||||||
ClientViewModel model = new ClientViewModel()
|
ClientModifyViewModel model = new ClientModifyViewModel()
|
||||||
{
|
{
|
||||||
Id = foundClient.ClientId,
|
Id = foundClient.ClientId,
|
||||||
Name = foundClient.ClientName,
|
Name = foundClient.ClientName,
|
||||||
HomepageUrl = foundClient.ClientUri,
|
HomepageUrl = foundClient.ClientUri,
|
||||||
LogoUrl = foundClient.LogoUri,
|
LogoUrl = foundClient.LogoUri,
|
||||||
CallbackUrl = string.Join(',', foundClient.RedirectUris),
|
CallbackUrl = string.Join(',', foundClient.RedirectUris),
|
||||||
AllowedScopes = foundClient.AllowedScopes
|
AllowedScopes = foundClient.AllowedScopes,
|
||||||
|
GrantType = IdentityHelper.GrantsToGrantType(foundClient.AllowedGrantTypes.ToArray()).ToString()
|
||||||
};
|
};
|
||||||
|
|
||||||
return Json(new { result = true, client = model });
|
return Json(new { result = true, client = model });
|
||||||
@ -1304,7 +1316,7 @@ namespace Teknik.Areas.Users.Controllers
|
|||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[ValidateAntiForgeryToken]
|
[ValidateAntiForgeryToken]
|
||||||
public async Task<IActionResult> EditClient(string clientId, string name, string homepageUrl, string logoUrl, string callbackUrl, [FromServices] ICompositeViewEngine viewEngine)
|
public async Task<IActionResult> EditClient(string clientId, string name, string homepageUrl, string logoUrl, string callbackUrl, IdentityClientGrant grantType, string scopes, [FromServices] ICompositeViewEngine viewEngine)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -1325,7 +1337,16 @@ namespace Teknik.Areas.Users.Controllers
|
|||||||
return Json(new { error = "Client does not exist" });
|
return Json(new { error = "Client does not exist" });
|
||||||
|
|
||||||
// Validate the code with the identity server
|
// Validate the code with the identity server
|
||||||
var result = await IdentityHelper.EditClient(_config, User.Identity.Name, clientId, name, homepageUrl, logoUrl, callbackUrl);
|
var result = await IdentityHelper.EditClient(
|
||||||
|
_config,
|
||||||
|
User.Identity.Name,
|
||||||
|
clientId,
|
||||||
|
name,
|
||||||
|
homepageUrl,
|
||||||
|
logoUrl,
|
||||||
|
callbackUrl,
|
||||||
|
IdentityHelper.GrantTypeToGrants(grantType),
|
||||||
|
scopes.Split(','));
|
||||||
|
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
@ -1337,6 +1358,8 @@ namespace Teknik.Areas.Users.Controllers
|
|||||||
model.HomepageUrl = homepageUrl;
|
model.HomepageUrl = homepageUrl;
|
||||||
model.LogoUrl = logoUrl;
|
model.LogoUrl = logoUrl;
|
||||||
model.CallbackUrl = callbackUrl;
|
model.CallbackUrl = callbackUrl;
|
||||||
|
model.GrantType = grantType;
|
||||||
|
model.AllowedScopes = scopes.Split(',');
|
||||||
|
|
||||||
string renderedView = await RenderPartialViewToString(viewEngine, "~/Areas/User/Views/User/Settings/ClientView.cshtml", model);
|
string renderedView = await RenderPartialViewToString(viewEngine, "~/Areas/User/Views/User/Settings/ClientView.cshtml", model);
|
||||||
|
|
||||||
|
@ -71,6 +71,47 @@ namespace Teknik.Areas.Users.Utility
|
|||||||
return new IdentityResult() { Success = false, Message = "HTTP Error: " + response.StatusCode + " | " + (await response.Content.ReadAsStringAsync()) };
|
return new IdentityResult() { Success = false, Message = "HTTP Error: " + response.StatusCode + " | " + (await response.Content.ReadAsStringAsync()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string[] GrantTypeToGrants(IdentityClientGrant grantType)
|
||||||
|
{
|
||||||
|
List<string> grants = new List<string>();
|
||||||
|
switch (grantType)
|
||||||
|
{
|
||||||
|
case IdentityClientGrant.Implicit:
|
||||||
|
grants.Add(GrantType.Implicit);
|
||||||
|
break;
|
||||||
|
case IdentityClientGrant.AuthorizationCode:
|
||||||
|
grants.Add(GrantType.AuthorizationCode);
|
||||||
|
break;
|
||||||
|
case IdentityClientGrant.ClientCredentials:
|
||||||
|
grants.Add(GrantType.ClientCredentials);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
grants.Add(GrantType.Hybrid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return grants.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IdentityClientGrant GrantsToGrantType(string[] grants)
|
||||||
|
{
|
||||||
|
if (grants.Contains(GrantType.Implicit))
|
||||||
|
{
|
||||||
|
return IdentityClientGrant.Implicit;
|
||||||
|
}
|
||||||
|
else if (grants.Contains(GrantType.AuthorizationCode))
|
||||||
|
{
|
||||||
|
return IdentityClientGrant.AuthorizationCode;
|
||||||
|
}
|
||||||
|
else if (grants.Contains(GrantType.ClientCredentials))
|
||||||
|
{
|
||||||
|
return IdentityClientGrant.ClientCredentials;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return IdentityClientGrant.ClientCredentials;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// API Functions
|
// API Functions
|
||||||
|
|
||||||
public static async Task<IdentityResult> CreateUser(Config config, string username, string password, string recoveryEmail)
|
public static async Task<IdentityResult> CreateUser(Config config, string username, string password, string recoveryEmail)
|
||||||
@ -350,7 +391,7 @@ namespace Teknik.Areas.Users.Utility
|
|||||||
throw new Exception(result.Message);
|
throw new Exception(result.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<IdentityResult> CreateClient(Config config, string username, string name, string homepageUrl, string logoUrl, string callbackUrl, params string[] allowedScopes)
|
public static async Task<IdentityResult> CreateClient(Config config, string username, string name, string homepageUrl, string logoUrl, string callbackUrl, string[] allowedGrants, string[] allowedScopes)
|
||||||
{
|
{
|
||||||
var manageUrl = CreateUrl(config, $"Manage/CreateClient");
|
var manageUrl = CreateUrl(config, $"Manage/CreateClient");
|
||||||
|
|
||||||
@ -362,12 +403,13 @@ namespace Teknik.Areas.Users.Utility
|
|||||||
homepageUrl = homepageUrl,
|
homepageUrl = homepageUrl,
|
||||||
logoUrl = logoUrl,
|
logoUrl = logoUrl,
|
||||||
callbackUrl = callbackUrl,
|
callbackUrl = callbackUrl,
|
||||||
allowedScopes = allowedScopes
|
allowedScopes = allowedScopes,
|
||||||
|
allowedGrants = allowedGrants
|
||||||
});
|
});
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<IdentityResult> EditClient(Config config, string username, string clientId, string name, string homepageUrl, string logoUrl, string callbackUrl)
|
public static async Task<IdentityResult> EditClient(Config config, string username, string clientId, string name, string homepageUrl, string logoUrl, string callbackUrl, string[] allowedGrants, string[] allowedScopes)
|
||||||
{
|
{
|
||||||
var manageUrl = CreateUrl(config, $"Manage/EditClient");
|
var manageUrl = CreateUrl(config, $"Manage/EditClient");
|
||||||
|
|
||||||
@ -379,7 +421,9 @@ namespace Teknik.Areas.Users.Utility
|
|||||||
name = name,
|
name = name,
|
||||||
homepageUrl = homepageUrl,
|
homepageUrl = homepageUrl,
|
||||||
logoUrl = logoUrl,
|
logoUrl = logoUrl,
|
||||||
callbackUrl = callbackUrl
|
callbackUrl = callbackUrl,
|
||||||
|
allowedScopes = allowedScopes,
|
||||||
|
allowedGrants = allowedGrants
|
||||||
});
|
});
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
20
Teknik/Areas/User/ViewModels/ClientModifyViewModel.cs
Normal file
20
Teknik/Areas/User/ViewModels/ClientModifyViewModel.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Teknik.Utilities;
|
||||||
|
using Teknik.ViewModels;
|
||||||
|
|
||||||
|
namespace Teknik.Areas.Users.ViewModels
|
||||||
|
{
|
||||||
|
public class ClientModifyViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string HomepageUrl { get; set; }
|
||||||
|
public string LogoUrl { get; set; }
|
||||||
|
public string CallbackUrl { get; set; }
|
||||||
|
public ICollection<string> AllowedScopes { get; set; }
|
||||||
|
public string GrantType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Teknik.Utilities;
|
||||||
using Teknik.ViewModels;
|
using Teknik.ViewModels;
|
||||||
|
|
||||||
namespace Teknik.Areas.Users.ViewModels
|
namespace Teknik.Areas.Users.ViewModels
|
||||||
@ -14,5 +15,6 @@ namespace Teknik.Areas.Users.ViewModels
|
|||||||
public string LogoUrl { get; set; }
|
public string LogoUrl { get; set; }
|
||||||
public string CallbackUrl { get; set; }
|
public string CallbackUrl { get; set; }
|
||||||
public ICollection<string> AllowedScopes { get; set; }
|
public ICollection<string> AllowedScopes { get; set; }
|
||||||
|
public IdentityClientGrant GrantType { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,33 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<strong>Allowed Scopes</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
@(string.Join(", ", Model.AllowedScopes))
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<strong>Grant Type</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
@Model.GrantType.GetDescription()
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div class="row">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
@ -39,7 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-8">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<strong>Authorization Callback Url</strong>
|
<strong>Authorization Callback Url</strong>
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml";
|
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<bundle src="css/user.settings.developer.min.css" append-version="true"></bundle>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var createClientURL = '@Url.SubRouteUrl("account", "User.Action", new { action = "CreateClient" })';
|
var createClientURL = '@Url.SubRouteUrl("account", "User.Action", new { action = "CreateClient" })';
|
||||||
var editClientURL = '@Url.SubRouteUrl("account", "User.Action", new { action = "EditClient" })';
|
var editClientURL = '@Url.SubRouteUrl("account", "User.Action", new { action = "EditClient" })';
|
||||||
@ -79,6 +81,47 @@
|
|||||||
<label for="clientCallbackUrl">Authorization callback URL <span class="text-danger">*</span></label>
|
<label for="clientCallbackUrl">Authorization callback URL <span class="text-danger">*</span></label>
|
||||||
<input type="text" class="form-control" id="clientCallbackUrl" name="clientCallbackUrl" data-val-required="The Authorization callback URL field is required." data-val="true" />
|
<input type="text" class="form-control" id="clientCallbackUrl" name="clientCallbackUrl" data-val-required="The Authorization callback URL field is required." data-val="true" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group" id="grantSection">
|
||||||
|
<label for="grantType">Grant Type</label>
|
||||||
|
<select class="form-control" name="grantType" id="grantType">
|
||||||
|
@foreach (IdentityClientGrant grant in Enum.GetValues(typeof(IdentityClientGrant)))
|
||||||
|
{
|
||||||
|
<!option value="@grant">@grant.GetDescription()</!option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" id="scopeSection">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<span class="glyphicon glyphicon-tasks"></span>
|
||||||
|
Allowed Scopes
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
@foreach (IdentityClientScope scope in Enum.GetValues(typeof(IdentityClientScope)))
|
||||||
|
{
|
||||||
|
|
||||||
|
<li class="list-group-item abc-checkbox">
|
||||||
|
<input class="consent-scopecheck @(scope.IsReadOnly() ? "default" : string.Empty)"
|
||||||
|
type="checkbox"
|
||||||
|
name="allowedScope"
|
||||||
|
id="scopes_@scope.GetDisplayName()"
|
||||||
|
value="@scope.GetDisplayName()"
|
||||||
|
checked="@scope.IsReadOnly()"
|
||||||
|
disabled="@scope.IsReadOnly()" />
|
||||||
|
<label for="ScopesConsented">
|
||||||
|
<strong>@scope.GetDisplayName()</strong>
|
||||||
|
</label>
|
||||||
|
@if (!string.IsNullOrEmpty(scope.GetDescription()))
|
||||||
|
{
|
||||||
|
<div class="consent-description">
|
||||||
|
<label for="scopes_@scope.GetDisplayName()">@scope.GetDescription()</label>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<button class="btn btn-primary pull-right hidden clientSubmit" id="clientCreateSubmit" type="submit" name="clientCreateSubmit">Create Client</button>
|
<button class="btn btn-primary pull-right hidden clientSubmit" id="clientCreateSubmit" type="submit" name="clientCreateSubmit">Create Client</button>
|
||||||
|
12
Teknik/Content/User/Settings/Developer.css
Normal file
12
Teknik/Content/User/Settings/Developer.css
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
.consent-scopecheck {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-description {
|
||||||
|
margin-left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-description label {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
@ -25,6 +25,11 @@ $(document).ready(function () {
|
|||||||
$("#createClient").click(function () {
|
$("#createClient").click(function () {
|
||||||
$('#clientModal').find('#clientCreateSubmit').removeClass('hidden');
|
$('#clientModal').find('#clientCreateSubmit').removeClass('hidden');
|
||||||
$('#clientModal').find('#clientCreateSubmit').text('Create Client');
|
$('#clientModal').find('#clientCreateSubmit').text('Create Client');
|
||||||
|
_.forEach($('#clientModal').find('#scopeSection :checkbox'), function (cb) {
|
||||||
|
if ($(cb).hasClass('default')) {
|
||||||
|
$(cb).prop('checked', true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('#clientModal').modal('show');
|
$('#clientModal').modal('show');
|
||||||
});
|
});
|
||||||
@ -101,6 +106,11 @@ function editClient(clientId) {
|
|||||||
$('#clientModal').find('#clientHomepageUrl').val(data.client.homepageUrl);
|
$('#clientModal').find('#clientHomepageUrl').val(data.client.homepageUrl);
|
||||||
$('#clientModal').find('#clientLogoUrl').val(data.client.logoUrl);
|
$('#clientModal').find('#clientLogoUrl').val(data.client.logoUrl);
|
||||||
$('#clientModal').find('#clientCallbackUrl').val(data.client.callbackUrl);
|
$('#clientModal').find('#clientCallbackUrl').val(data.client.callbackUrl);
|
||||||
|
$('#clientModal').find('#grantType').val(data.client.grantType);
|
||||||
|
|
||||||
|
_.forEach(data.client.allowedScopes, function (scope) {
|
||||||
|
$('#clientModal').find('#scopes_' + scope).prop('checked', true);
|
||||||
|
});
|
||||||
|
|
||||||
$('#clientModal').find('#clientEditSubmit').removeClass('hidden');
|
$('#clientModal').find('#clientEditSubmit').removeClass('hidden');
|
||||||
$('#clientModal').find('#clientEditSubmit').text('Save Client');
|
$('#clientModal').find('#clientEditSubmit').text('Save Client');
|
||||||
@ -168,7 +178,7 @@ function deleteClient(clientId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function saveClientInfo(url, submitText, submitActionText, callback) {
|
function saveClientInfo(url, submitText, submitActionText, callback) {
|
||||||
var clientId, name, homepageUrl, logoUrl, callbackUrl;
|
var clientId, name, homepageUrl, logoUrl, callbackUrl, grantType, scopes;
|
||||||
disableButton('.clientSubmit', submitActionText);
|
disableButton('.clientSubmit', submitActionText);
|
||||||
|
|
||||||
clientId = $('#clientModal').find('#clientId').val();
|
clientId = $('#clientModal').find('#clientId').val();
|
||||||
@ -176,11 +186,17 @@ function saveClientInfo(url, submitText, submitActionText, callback) {
|
|||||||
homepageUrl = $('#clientModal').find('#clientHomepageUrl').val();
|
homepageUrl = $('#clientModal').find('#clientHomepageUrl').val();
|
||||||
logoUrl = $('#clientModal').find('#clientLogoUrl').val();
|
logoUrl = $('#clientModal').find('#clientLogoUrl').val();
|
||||||
callbackUrl = $('#clientModal').find('#clientCallbackUrl').val();
|
callbackUrl = $('#clientModal').find('#clientCallbackUrl').val();
|
||||||
|
grantType = $('#clientModal').find('#grantType').val();
|
||||||
|
scopes = $('#clientModal').find('#scopeSection :checkbox:checked');
|
||||||
|
scopes = _.map(scopes, function (cb) {
|
||||||
|
return cb.value;
|
||||||
|
});
|
||||||
|
scopes = scopes.join(',');
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
url: url,
|
url: url,
|
||||||
data: AddAntiForgeryToken({ clientId: clientId, name: name, homepageUrl: homepageUrl, logoUrl: logoUrl, callbackUrl: callbackUrl }),
|
data: AddAntiForgeryToken({ clientId: clientId, name: name, homepageUrl: homepageUrl, logoUrl: logoUrl, callbackUrl: callbackUrl, grantType: grantType, scopes: scopes }),
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
if (response.result) {
|
if (response.result) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
|
@ -155,6 +155,9 @@ function clearInputs(parent) {
|
|||||||
$(parent).find('textarea').each(function () {
|
$(parent).find('textarea').each(function () {
|
||||||
$(this).val('');
|
$(this).val('');
|
||||||
});
|
});
|
||||||
|
$(parent).find('input:checkbox').each(function () {
|
||||||
|
$(this).prop('checked', false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
String.prototype.hashCode = function () {
|
String.prototype.hashCode = function () {
|
||||||
|
@ -263,6 +263,12 @@
|
|||||||
"./wwwroot/js/app/User/DeveloperSettings.js"
|
"./wwwroot/js/app/User/DeveloperSettings.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"outputFileName": "./wwwroot/css/user.settings.developer.min.css",
|
||||||
|
"inputFiles": [
|
||||||
|
"./wwwroot/css/app/User/Settings/Developer.css"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"outputFileName": "./wwwroot/js/user.settings.upload.min.js",
|
"outputFileName": "./wwwroot/js/user.settings.upload.min.js",
|
||||||
"inputFiles": [
|
"inputFiles": [
|
||||||
|
54
Utilities/Extensions.cs
Normal file
54
Utilities/Extensions.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Teknik.Utilities
|
||||||
|
{
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
public static string GetDescription<T>(this T value)
|
||||||
|
{
|
||||||
|
FieldInfo fi = value.GetType().GetField(value.ToString());
|
||||||
|
|
||||||
|
DescriptionAttribute[] attributes = fi.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];
|
||||||
|
|
||||||
|
if (attributes != null && attributes.Any())
|
||||||
|
{
|
||||||
|
return attributes.First().Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetDisplayName<T>(this T value)
|
||||||
|
{
|
||||||
|
FieldInfo fi = value.GetType().GetField(value.ToString());
|
||||||
|
|
||||||
|
DisplayNameAttribute[] attributes = fi.GetCustomAttributes(typeof(DisplayNameAttribute), false) as DisplayNameAttribute[];
|
||||||
|
|
||||||
|
if (attributes != null && attributes.Any())
|
||||||
|
{
|
||||||
|
return attributes.First().DisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsReadOnly<T>(this T value)
|
||||||
|
{
|
||||||
|
FieldInfo fi = value.GetType().GetField(value.ToString());
|
||||||
|
|
||||||
|
ReadOnlyAttribute[] attributes = fi.GetCustomAttributes(typeof(ReadOnlyAttribute), false) as ReadOnlyAttribute[];
|
||||||
|
|
||||||
|
if (attributes != null && attributes.Any())
|
||||||
|
{
|
||||||
|
return attributes.First().IsReadOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Utilities/IdentityClientGrant.cs
Normal file
17
Utilities/IdentityClientGrant.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Teknik.Utilities
|
||||||
|
{
|
||||||
|
public enum IdentityClientGrant
|
||||||
|
{
|
||||||
|
[Description("Authorization Code")]
|
||||||
|
AuthorizationCode,
|
||||||
|
[Description("Client Credentials")]
|
||||||
|
ClientCredentials,
|
||||||
|
[Description("Implicit")]
|
||||||
|
Implicit,
|
||||||
|
}
|
||||||
|
}
|
30
Utilities/IdentityClientScope.cs
Normal file
30
Utilities/IdentityClientScope.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Teknik.Utilities
|
||||||
|
{
|
||||||
|
public enum IdentityClientScope
|
||||||
|
{
|
||||||
|
[DisplayName("openid")]
|
||||||
|
[Description("The user identifier")]
|
||||||
|
[ReadOnly(true)]
|
||||||
|
openid,
|
||||||
|
[DisplayName("role")]
|
||||||
|
[Description("The user role")]
|
||||||
|
role,
|
||||||
|
[DisplayName("account-info")]
|
||||||
|
[Description("A user's account information")]
|
||||||
|
accountInfo,
|
||||||
|
[DisplayName("security-info")]
|
||||||
|
[Description("A user's security information")]
|
||||||
|
securityInfo,
|
||||||
|
[DisplayName("teknik-api.read")]
|
||||||
|
[Description("Read access to the Teknik API")]
|
||||||
|
teknikApiRead,
|
||||||
|
[DisplayName("teknik-api.write")]
|
||||||
|
[Description("Write access to the Teknik API")]
|
||||||
|
teknikApiWrite,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user