├── .gitignore ├── IdentityServer_aspcore └── IdSvrHost │ ├── Configuration │ ├── Clients.cs │ ├── Scopes.cs │ └── Users.cs │ ├── Extensions │ └── CustomGrantValidator.cs │ ├── IdSvrHost.xproj │ ├── Properties │ └── launchSettings.json │ ├── Startup.cs │ ├── UI │ ├── Consent │ │ ├── ConsentController.cs │ │ ├── ConsentInputModel.cs │ │ ├── ConsentResult.cs │ │ ├── ConsentViewModel.cs │ │ └── Views │ │ │ ├── Index.cshtml │ │ │ └── _ScopeListItem.cshtml │ ├── CustomViewLocationExpander.cs │ ├── Error │ │ ├── ErrorController.cs │ │ └── ErrorViewModel.cs │ ├── Home │ │ ├── HomeController.cs │ │ └── Views │ │ │ └── Index.cshtml │ ├── Login │ │ ├── LoginController.cs │ │ ├── LoginInputModel.cs │ │ ├── LoginService.cs │ │ ├── LoginViewModel.cs │ │ ├── SignInResult.cs │ │ └── Views │ │ │ └── Index.cshtml │ ├── Logout │ │ ├── LoggedOutViewModel.cs │ │ ├── LogoutController.cs │ │ ├── LogoutViewModel.cs │ │ └── Views │ │ │ ├── Index.cshtml │ │ │ └── LoggedOut.cshtml │ ├── SharedViews │ │ ├── Error.cshtml │ │ ├── _Layout.cshtml │ │ └── _ValidationSummary.cshtml │ ├── TagHelpers │ │ └── HideShowTagHelpers.cs │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml │ ├── appsettings.json │ ├── idsrv4test.pfx │ ├── project.json │ ├── project.lock.json │ └── wwwroot │ ├── css │ ├── site.css │ ├── site.less │ └── site.min.css │ ├── favicon.ico │ ├── icon.jpg │ ├── icon.png │ ├── lib │ ├── bootstrap │ │ ├── css │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ └── bootstrap.min.css │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ └── js │ │ │ ├── bootstrap.js │ │ │ └── bootstrap.min.js │ └── jquery │ │ ├── jquery.js │ │ ├── jquery.min.js │ │ └── jquery.min.map │ └── web.config ├── LICENSE ├── README.md └── ServiceStack ├── .vs └── config │ └── applicationhost.config ├── Punchard.ServiceStackJWT.sln ├── Punchard.ServiceStackJWTExample.ServiceInterface ├── MyServices.cs ├── MyServicesAuth.cs ├── Properties │ └── AssemblyInfo.cs ├── Punchard.ServiceStackJWTExampleServiceInterface.csproj ├── app.config └── packages.config ├── Punchard.ServiceStackJWTExample.ServiceModel ├── Hello.cs ├── HelloAuth.cs ├── Properties │ └── AssemblyInfo.cs ├── Punchard.ServiceStackJWTExample.ServiceModel.csproj └── packages.config ├── Punchard.ServiceStackJWTExample.Tests ├── Properties │ └── AssemblyInfo.cs ├── Punchard.ServiceStackJWTExample.Tests.csproj ├── UnitTests.cs ├── app.config └── packages.config ├── Punchard.ServiceStackJWTExample ├── .vs │ └── config │ │ └── applicationhost.config ├── AppHost.cs ├── Global.asax ├── Global.asax.cs ├── Properties │ └── AssemblyInfo.cs ├── Punchard.ServiceStackJWTExample.csproj ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── default.html └── packages.config ├── Punchcard.Angular1JWT ├── .bowerrc ├── .gitignore ├── .jscsrc ├── .jshintrc ├── Properties │ └── AssemblyInfo.cs ├── Punchcard.Angular1JWT.csproj ├── README.md ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── bower.json ├── gulp.config.json ├── gulp │ ├── commentWrapper.js │ ├── common.js │ └── copyright.js ├── gulpfile.js ├── iisnode.yml ├── karma.conf.js ├── package.json ├── packages.config └── src │ ├── client │ ├── app │ │ ├── Claims │ │ │ ├── claims.html │ │ │ ├── claims.js │ │ │ ├── claims.module.js │ │ │ └── config.route.js │ │ ├── app.module.js │ │ ├── blocks │ │ │ ├── exception │ │ │ │ ├── exception-handler.provider.js │ │ │ │ ├── exception.js │ │ │ │ └── exception.module.js │ │ │ ├── logger │ │ │ │ ├── logger.js │ │ │ │ └── logger.module.js │ │ │ └── router │ │ │ │ ├── routehelper.js │ │ │ │ └── router.module.js │ │ ├── core │ │ │ ├── AuthService.js │ │ │ ├── config.js │ │ │ ├── constants.js │ │ │ ├── core.module.js │ │ │ └── dataservice.js │ │ ├── dashboard │ │ │ ├── config.route.js │ │ │ ├── dashboard.html │ │ │ ├── dashboard.js │ │ │ └── dashboard.module.js │ │ ├── layout │ │ │ ├── layout.module.js │ │ │ ├── shell.html │ │ │ ├── shell.js │ │ │ ├── sidebar.html │ │ │ ├── sidebar.js │ │ │ └── topnav.html │ │ └── widgets │ │ │ ├── ccSidebar.js │ │ │ ├── ccSpinner.js │ │ │ ├── ccWidgetClose.js │ │ │ ├── ccWidgetHeader.js │ │ │ ├── ccWidgetMinimize.js │ │ │ ├── widgetheader.html │ │ │ └── widgets.module.js │ ├── callback.html │ ├── content │ │ ├── customtheme.css │ │ ├── images │ │ │ ├── AngularJS-small.png │ │ │ ├── avengersicon-xs.png │ │ │ ├── avengersicon.png │ │ │ ├── busy.gif │ │ │ ├── gg.png │ │ │ └── gruntjs.jpg │ │ └── styles.css │ ├── index.html │ └── test │ │ ├── .jshintrc │ │ ├── lib │ │ ├── bindPolyfill.js │ │ ├── mockData.js │ │ └── specHelper.js │ │ ├── midway │ │ ├── controller.spec.js │ │ ├── dataservice.spec.js │ │ ├── template.spec.js │ │ └── view-requests.spec.js │ │ └── specs │ │ ├── avengers-route.spec.js │ │ ├── avengers.spec.js │ │ ├── ccSidebar.spec.js │ │ ├── dashboard-route.spec.js │ │ ├── dashboard.spec.js │ │ ├── dataservice.spec.js │ │ ├── exception-handler.provider.spec.js │ │ └── sidebar.spec.js │ └── server │ ├── app.js │ ├── data │ ├── maa.json │ ├── marvelavengersalliance.json │ └── thor.json │ ├── favicon.ico │ └── routes │ ├── index.js │ └── utils │ ├── errorHandler.js │ └── jsonfileservice.js └── Punchcard.ServiceStackJWT ├── JsonWebToken.cs ├── JsonWebTokenAuthProvider.cs ├── Properties └── AssemblyInfo.cs ├── Punchcard.ServiceStackJWT.csproj ├── app.config └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Visual Studio Project # 2 | ################### 3 | *.user 4 | *.gpState 5 | *.suo 6 | **/bin 7 | **/obj 8 | /packages 9 | /WevAPI_aspcore 10 | 11 | # Ignore Node & Bower 12 | ################### 13 | **/node_modules 14 | /modular/client/build 15 | /modular/build 16 | **/bower_components 17 | **/test/coverage 18 | /reports 19 | 20 | 21 | # mongo db 22 | ################### 23 | #Don't commit Mongo Database files 24 | *.lock 25 | *.0 26 | *.1 27 | *.ns 28 | journal 29 | 30 | # Ignore Web Storm # 31 | .idea 32 | 33 | # Compiled source # 34 | ################### 35 | *.com 36 | *.class 37 | *.dll 38 | *.exe 39 | *.o 40 | *.so 41 | report/ 42 | 43 | # Packages # 44 | ############ 45 | # it's better to unpack these files and commit the raw source 46 | # git has its own built in compression methods 47 | *.7z 48 | *.dmg 49 | *.gz 50 | *.iso 51 | *.jar 52 | *.rar 53 | *.tar 54 | *.xap 55 | *.zip 56 | 57 | # Logs and databases # 58 | ###################### 59 | *.log 60 | *.sql 61 | *.sqlite 62 | # *.sdf 63 | *.mdf 64 | *.ldf 65 | 66 | # OS generated files # 67 | ###################### 68 | .DS_Store* 69 | ehthumbs.db 70 | Icon? 71 | Thumbs.db 72 | packages 73 | 74 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/Configuration/Scopes.cs: -------------------------------------------------------------------------------- 1 | using IdentityServer4.Core.Models; 2 | using System.Collections.Generic; 3 | 4 | namespace IdSvrHost.Configuration 5 | { 6 | public class Scopes 7 | { 8 | public static IEnumerable Get() 9 | { 10 | return new List 11 | { 12 | StandardScopes.OpenId, 13 | StandardScopes.ProfileAlwaysInclude, 14 | StandardScopes.EmailAlwaysInclude, 15 | StandardScopes.OfflineAccess, 16 | StandardScopes.RolesAlwaysInclude, 17 | 18 | new Scope 19 | { 20 | Name = "api1", 21 | DisplayName = "API 1", 22 | Description = "API 1 features and data", 23 | Type = ScopeType.Resource, 24 | 25 | ScopeSecrets = new List 26 | { 27 | new Secret("secret".Sha256()) 28 | }, 29 | Claims = new List 30 | { 31 | new ScopeClaim("role") 32 | } 33 | }, 34 | new Scope 35 | { 36 | Name = "api2", 37 | DisplayName = "API 2", 38 | Description = "API 2 features and data, which are better than API 1", 39 | Type = ScopeType.Resource 40 | } 41 | }; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/Configuration/Users.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Dominick Baier, Brock Allen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | using IdentityServer4.Core; 18 | using IdentityServer4.Core.Services.InMemory; 19 | using System.Collections.Generic; 20 | using System.Security.Claims; 21 | 22 | namespace IdSvrHost.Configuration 23 | { 24 | static class Users 25 | { 26 | public static List Get() 27 | { 28 | var users = new List 29 | { 30 | new InMemoryUser{Subject = "818727", Username = "alice", Password = "alice", 31 | Claims = new Claim[] 32 | { 33 | new Claim(Constants.ClaimTypes.Name, "Alice Smith"), 34 | new Claim(Constants.ClaimTypes.GivenName, "Alice"), 35 | new Claim(Constants.ClaimTypes.FamilyName, "Smith"), 36 | new Claim(Constants.ClaimTypes.Email, "AliceSmith@email.com"), 37 | new Claim(Constants.ClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), 38 | new Claim(Constants.ClaimTypes.Role, "Admin"), 39 | new Claim(Constants.ClaimTypes.Role, "Geek"), 40 | new Claim(Constants.ClaimTypes.WebSite, "http://alice.com"), 41 | new Claim(Constants.ClaimTypes.Address, @"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", Constants.ClaimValueTypes.Json) 42 | } 43 | }, 44 | new InMemoryUser{Subject = "88421113", Username = "bob", Password = "bob", 45 | Claims = new Claim[] 46 | { 47 | new Claim(Constants.ClaimTypes.Name, "Bob Smith"), 48 | new Claim(Constants.ClaimTypes.GivenName, "Bob"), 49 | new Claim(Constants.ClaimTypes.FamilyName, "Smith"), 50 | new Claim(Constants.ClaimTypes.Email, "BobSmith@email.com"), 51 | new Claim(Constants.ClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), 52 | new Claim(Constants.ClaimTypes.Role, "Developer"), 53 | new Claim(Constants.ClaimTypes.Role, "Geek"), 54 | new Claim(Constants.ClaimTypes.WebSite, "http://bob.com"), 55 | new Claim(Constants.ClaimTypes.Address, @"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", Constants.ClaimValueTypes.Json) 56 | } 57 | }, 58 | }; 59 | 60 | return users; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/Extensions/CustomGrantValidator.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Dominick Baier, Brock Allen 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | using IdentityServer4.Core.Validation; 18 | using System.Threading.Tasks; 19 | 20 | namespace IdSvrHost.Extensions 21 | { 22 | public class CustomGrantValidator : ICustomGrantValidator 23 | { 24 | public Task ValidateAsync(ValidatedTokenRequest request) 25 | { 26 | var credential = request.Raw.Get("custom_credential"); 27 | 28 | if (credential != null) 29 | { 30 | // valid credential 31 | return Task.FromResult(new CustomGrantValidationResult("818727", "custom")); 32 | } 33 | else 34 | { 35 | // custom error message 36 | return Task.FromResult(new CustomGrantValidationResult("invalid custom credential")); 37 | } 38 | } 39 | 40 | public string GrantType 41 | { 42 | get { return "custom"; } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/IdSvrHost.xproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 154ccedc-cfd5-4b7a-9000-fc454ea86362 10 | IdSvrHost 11 | ..\..\artifacts\obj\$(MSBuildProjectName) 12 | ..\..\artifacts\bin\$(MSBuildProjectName)\ 13 | 14 | 15 | 2.0 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:22530/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "launchUrl": "http://localhost:22530/", 15 | "environmentVariables": { 16 | "Hosting:Environment": "Development" 17 | }, 18 | "sdkVersion": "dnx-clr-win-x86.1.0.0-rc1-final" 19 | }, 20 | "web": { 21 | "commandName": "web", 22 | "environmentVariables": { 23 | "Hosting:Environment": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNet.Builder; 6 | using Microsoft.AspNet.Hosting; 7 | using Microsoft.Extensions.Configuration; 8 | using Microsoft.Extensions.DependencyInjection; 9 | using Microsoft.Extensions.Logging; 10 | using IdSvrHost.Configuration; 11 | using IdSvrHost.Extensions; 12 | using Microsoft.Extensions.PlatformAbstractions; 13 | using System.Security.Cryptography.X509Certificates; 14 | using System.IO; 15 | 16 | namespace IdSvrHost2 17 | { 18 | public class Startup 19 | { 20 | private readonly IApplicationEnvironment _environment; 21 | 22 | public Startup(IApplicationEnvironment environment) 23 | { 24 | _environment = environment; 25 | } 26 | 27 | public void ConfigureServices(IServiceCollection services) 28 | { 29 | //TODO: This is the demo cert, replace with our own 30 | var cert = new X509Certificate2(Path.Combine(_environment.ApplicationBasePath, "idsrv4test.pfx"), "idsrv3test"); 31 | 32 | var builder = services.AddIdentityServer(options => 33 | { 34 | options.SigningCertificate = cert; 35 | options.SiteName = "Punchcard Identity Server (STS)"; 36 | //options.IssuerUri = "http://localhost:22530/identity"; 37 | //publicOrigin? - doesn't seem to be available in v4 38 | 39 | }); 40 | 41 | builder.AddInMemoryClients(Clients.Get()); 42 | builder.AddInMemoryScopes(Scopes.Get()); 43 | builder.AddInMemoryUsers(Users.Get()); 44 | 45 | builder.AddCustomGrantValidator(); 46 | 47 | 48 | // for the UI 49 | services 50 | .AddMvc() 51 | .AddRazorOptions(razor => 52 | { 53 | razor.ViewLocationExpanders.Add(new IdSvrHost.UI.CustomViewLocationExpander()); 54 | }); 55 | services.AddTransient(); 56 | } 57 | 58 | public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) 59 | { 60 | loggerFactory.AddConsole(LogLevel.Verbose); 61 | loggerFactory.AddDebug(LogLevel.Verbose); 62 | 63 | app.UseDeveloperExceptionPage(); 64 | app.UseIISPlatformHandler(); 65 | 66 | app.UseIdentityServer(); 67 | 68 | app.UseStaticFiles(); 69 | app.UseMvcWithDefaultRoute(); 70 | } 71 | 72 | public static void Main(string[] args) => WebApplication.Run(args); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Consent/ConsentController.cs: -------------------------------------------------------------------------------- 1 | using IdentityServer4.Core; 2 | using IdentityServer4.Core.Services; 3 | using Microsoft.AspNet.Mvc; 4 | using Microsoft.Extensions.Logging; 5 | using System.Linq; 6 | using System.Security.Claims; 7 | using System.Threading.Tasks; 8 | using System; 9 | using IdentityServer4.Core.Models; 10 | 11 | namespace IdSvrHost.UI.Consent 12 | { 13 | public class ConsentController : Controller 14 | { 15 | private readonly ILogger _logger; 16 | private readonly IClientStore _clientStore; 17 | private readonly ConsentInteraction _consentInteraction; 18 | private readonly IScopeStore _scopeStore; 19 | private readonly ILocalizationService _localization; 20 | 21 | public ConsentController( 22 | ILogger logger, 23 | ConsentInteraction consentInteraction, 24 | IClientStore clientStore, 25 | IScopeStore scopeStore, 26 | ILocalizationService localization) 27 | { 28 | _logger = logger; 29 | _consentInteraction = consentInteraction; 30 | _clientStore = clientStore; 31 | _scopeStore = scopeStore; 32 | _localization = localization; 33 | } 34 | 35 | [HttpGet(Constants.RoutePaths.Consent, Name = "Consent")] 36 | public async Task Index(string id) 37 | { 38 | var vm = await BuildViewModelAsync(id); 39 | if (vm != null) 40 | { 41 | return View("Index", vm); 42 | } 43 | 44 | return View("Error"); 45 | } 46 | 47 | [HttpPost(Constants.RoutePaths.Consent)] 48 | [ValidateAntiForgeryToken] 49 | public async Task Index(string button, string id, ConsentInputModel model) 50 | { 51 | if (button == "no") 52 | { 53 | return new ConsentResult(id, ConsentResponse.Denied); 54 | } 55 | else if (button == "yes" && model != null) 56 | { 57 | if (model.ScopesConsented != null && model.ScopesConsented.Any()) 58 | { 59 | return new ConsentResult(id, new ConsentResponse 60 | { 61 | RememberConsent = model.RememberConsent, 62 | ScopesConsented = model.ScopesConsented 63 | }); 64 | } 65 | else 66 | { 67 | ModelState.AddModelError("", "You must pick at least one permission."); 68 | } 69 | } 70 | else 71 | { 72 | ModelState.AddModelError("", "Invalid Selection"); 73 | } 74 | 75 | var vm = await BuildViewModelAsync(id, model); 76 | if (vm != null) 77 | { 78 | return View("Index", vm); 79 | } 80 | 81 | return View("Error"); 82 | } 83 | 84 | async Task BuildConsentResponse(string id, string[] scopesConsented, bool rememberConsent) 85 | { 86 | if (id != null) 87 | { 88 | var request = await _consentInteraction.GetRequestAsync(id); 89 | } 90 | 91 | return View("Error"); 92 | } 93 | 94 | async Task BuildViewModelAsync(string id, ConsentInputModel model = null) 95 | { 96 | if (id != null) 97 | { 98 | var request = await _consentInteraction.GetRequestAsync(id); 99 | if (request != null) 100 | { 101 | var client = await _clientStore.FindClientByIdAsync(request.ClientId); 102 | if (client != null) 103 | { 104 | var scopes = await _scopeStore.FindScopesAsync(request.ScopesRequested); 105 | if (scopes != null && scopes.Any()) 106 | { 107 | return new ConsentViewModel(model, id, request, client, scopes, _localization); 108 | } 109 | else 110 | { 111 | _logger.LogError("No scopes matching: {0}", request.ScopesRequested.Aggregate((x, y) => x + ", " + y)); 112 | } 113 | } 114 | else 115 | { 116 | _logger.LogError("Invalid client id: {0}", request.ClientId); 117 | } 118 | } 119 | else 120 | { 121 | _logger.LogError("No consent request matching id: {0}", id); 122 | } 123 | } 124 | else 125 | { 126 | _logger.LogError("No id passed"); 127 | } 128 | 129 | return null; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Consent/ConsentInputModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace IdSvrHost.UI.Consent 7 | { 8 | public class ConsentInputModel 9 | { 10 | public IEnumerable ScopesConsented { get; set; } 11 | public bool RememberConsent { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Consent/ConsentResult.cs: -------------------------------------------------------------------------------- 1 | using IdentityServer4.Core.Models; 2 | using IdentityServer4.Core.Services; 3 | using Microsoft.AspNet.Mvc; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | 10 | namespace IdSvrHost.UI.Consent 11 | { 12 | public class ConsentResult : IActionResult 13 | { 14 | private readonly string _requestId; 15 | private readonly ConsentResponse _response; 16 | 17 | public ConsentResult(string requestId, ConsentResponse response) 18 | { 19 | _requestId = requestId; 20 | _response = response; 21 | } 22 | 23 | public async Task ExecuteResultAsync(ActionContext context) 24 | { 25 | var interaction = context.HttpContext.RequestServices.GetRequiredService(); 26 | await interaction.ProcessResponseAsync(_requestId, _response); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Consent/ConsentViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using IdentityServer4.Core.Extensions; 6 | using IdentityServer4.Core.Models; 7 | using IdentityServer4.Core.Services; 8 | 9 | namespace IdSvrHost.UI.Consent 10 | { 11 | public class ConsentViewModel : ConsentInputModel 12 | { 13 | public ConsentViewModel(ConsentInputModel model, string consentId, ConsentRequest request, Client client, IEnumerable scopes, ILocalizationService localization) 14 | { 15 | RememberConsent = model?.RememberConsent ?? true; 16 | ScopesConsented = model?.ScopesConsented ?? Enumerable.Empty(); 17 | 18 | ConsentId = consentId; 19 | 20 | ClientName = client.ClientName; 21 | ClientUrl = client.ClientUri; 22 | ClientLogoUrl = client.LogoUri; 23 | AllowRememberConsent = client.AllowRememberConsent; 24 | 25 | IdentityScopes = scopes.Where(x => x.Type == ScopeType.Identity).Select(x => new ScopeViewModel(localization, x, ScopesConsented.Contains(x.Name) || model == null)).ToArray(); 26 | ResourceScopes = scopes.Where(x => x.Type == ScopeType.Resource).Select(x => new ScopeViewModel(localization, x, ScopesConsented.Contains(x.Name) || model == null)).ToArray(); 27 | } 28 | 29 | public string ConsentId { get; set; } 30 | 31 | public string ClientName { get; set; } 32 | public string ClientUrl { get; set; } 33 | public string ClientLogoUrl { get; set; } 34 | public bool AllowRememberConsent { get; set; } 35 | 36 | public IEnumerable IdentityScopes { get; set; } 37 | public IEnumerable ResourceScopes { get; set; } 38 | } 39 | 40 | public class ScopeViewModel 41 | { 42 | public ScopeViewModel(ILocalizationService localization, Scope scope, bool check) 43 | { 44 | Name = scope.Name; 45 | DisplayName = localization.GetScopeDisplayName(scope.Name) ?? scope.DisplayName; 46 | Description = localization.GetScopeDescription(scope.Name) ?? scope.Description; 47 | Emphasize = scope.Emphasize; 48 | Required = scope.Required; 49 | Checked = check || scope.Required; 50 | } 51 | 52 | public string Name { get; set; } 53 | public string DisplayName { get; set; } 54 | public string Description { get; set; } 55 | public bool Emphasize { get; set; } 56 | public bool Required { get; set; } 57 | public bool Checked { get; set; } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Consent/Views/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IdSvrHost.UI.Consent.ConsentViewModel 2 | 3 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Consent/Views/_ScopeListItem.cshtml: -------------------------------------------------------------------------------- 1 | @model IdSvrHost.UI.Consent.ScopeViewModel 2 | 3 |
  • 4 | 19 | (required) 20 | 23 |
  • -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/CustomViewLocationExpander.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Mvc.Razor; 2 | using System.Collections.Generic; 3 | 4 | namespace IdSvrHost.UI 5 | { 6 | public class CustomViewLocationExpander : IViewLocationExpander 7 | { 8 | public IEnumerable ExpandViewLocations( 9 | ViewLocationExpanderContext context, 10 | IEnumerable viewLocations) 11 | { 12 | yield return "~/UI/{1}/Views/{0}.cshtml"; 13 | yield return "~/UI/SharedViews/{0}.cshtml"; 14 | } 15 | 16 | public void PopulateValues(ViewLocationExpanderContext context) 17 | { 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Error/ErrorController.cs: -------------------------------------------------------------------------------- 1 | using IdentityServer4.Core; 2 | using IdentityServer4.Core.Services; 3 | using Microsoft.AspNet.Mvc; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace IdSvrHost.UI.Error 10 | { 11 | public class ErrorController : Controller 12 | { 13 | private readonly ErrorInteraction _errorInteraction; 14 | 15 | public ErrorController(ErrorInteraction errorInteraction) 16 | { 17 | _errorInteraction = errorInteraction; 18 | } 19 | 20 | [Route(Constants.RoutePaths.Error, Name ="Error")] 21 | public async Task Index(string id) 22 | { 23 | var vm = new ErrorViewModel(); 24 | 25 | if (id != null) 26 | { 27 | var message = await _errorInteraction.GetRequestAsync(id); 28 | if (message != null) 29 | { 30 | vm.Error = message; 31 | } 32 | } 33 | 34 | return View("Error", vm); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Error/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | using IdentityServer4.Core.Models; 2 | 3 | namespace IdSvrHost.UI.Error 4 | { 5 | public class ErrorViewModel 6 | { 7 | public ErrorMessage Error { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Home/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Mvc; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdSvrHost.UI.Home 8 | { 9 | public class HomeController : Controller 10 | { 11 | [Route("/")] 12 | public IActionResult Index() 13 | { 14 | return View(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Home/Views/Index.cshtml: -------------------------------------------------------------------------------- 1 |  2 |
    3 | 12 | 13 |
    14 |
    15 |

    16 | IdentityServer publishes a 17 | discovery document 18 | where you can find metadata and links to all the endpoints, key material, etc. 19 |

    20 |
    21 |
    22 |
    23 |
    24 |

    25 | Here are links to the 26 | source code repository, 27 | and ready to use samples. 28 |

    29 |
    30 |
    31 |
    32 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Login/LoginController.cs: -------------------------------------------------------------------------------- 1 | using IdentityModel; 2 | using IdentityServer4.Core; 3 | using IdentityServer4.Core.Services; 4 | using Microsoft.AspNet.Mvc; 5 | using System; 6 | using System.Linq; 7 | using System.Security.Claims; 8 | using System.Threading.Tasks; 9 | 10 | namespace IdSvrHost.UI.Login 11 | { 12 | public class LoginController : Controller 13 | { 14 | private readonly LoginService _loginService; 15 | private readonly SignInInteraction _signInInteraction; 16 | 17 | public LoginController( 18 | LoginService loginService, 19 | SignInInteraction signInInteraction) 20 | { 21 | _loginService = loginService; 22 | _signInInteraction = signInInteraction; 23 | } 24 | 25 | [HttpGet(Constants.RoutePaths.Login, Name = "Login")] 26 | public async Task Index(string id) 27 | { 28 | var vm = new LoginViewModel(); 29 | 30 | if (id != null) 31 | { 32 | var request = await _signInInteraction.GetRequestAsync(id); 33 | if (request != null) 34 | { 35 | vm.Username = request.LoginHint; 36 | vm.SignInId = id; 37 | } 38 | } 39 | 40 | return View(vm); 41 | } 42 | 43 | [HttpPost(Constants.RoutePaths.Login)] 44 | [ValidateAntiForgeryToken] 45 | public async Task Index(LoginInputModel model) 46 | { 47 | if (ModelState.IsValid) 48 | { 49 | if (_loginService.ValidateCredentials(model.Username, model.Password)) 50 | { 51 | var user = _loginService.FindByUsername(model.Username); 52 | 53 | var name = user.Claims.Where(x => x.Type == Constants.ClaimTypes.Name).Select(x => x.Value).FirstOrDefault() ?? user.Username; 54 | 55 | var claims = new Claim[] { 56 | new Claim(Constants.ClaimTypes.Subject, user.Subject), 57 | new Claim(Constants.ClaimTypes.Name, name), 58 | new Claim(Constants.ClaimTypes.IdentityProvider, "idsvr"), 59 | new Claim(Constants.ClaimTypes.AuthenticationTime, DateTime.UtcNow.ToEpochTime().ToString()), 60 | }; 61 | var ci = new ClaimsIdentity(claims, "password", Constants.ClaimTypes.Name, Constants.ClaimTypes.Role); 62 | var cp = new ClaimsPrincipal(ci); 63 | 64 | await HttpContext.Authentication.SignInAsync(Constants.PrimaryAuthenticationType, cp); 65 | 66 | if (model.SignInId != null) 67 | { 68 | return new SignInResult(model.SignInId); 69 | } 70 | 71 | return Redirect("~/"); 72 | } 73 | 74 | ModelState.AddModelError("", "Invalid username or password."); 75 | } 76 | 77 | var vm = new LoginViewModel(model); 78 | return View(vm); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Login/LoginInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace IdSvrHost.UI.Login 4 | { 5 | public class LoginInputModel 6 | { 7 | [Required] 8 | public string Username { get; set; } 9 | [Required] 10 | public string Password { get; set; } 11 | public bool RememberLogin { get; set; } 12 | public string SignInId { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Login/LoginService.cs: -------------------------------------------------------------------------------- 1 | using IdentityServer4.Core.Services.InMemory; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | 5 | namespace IdSvrHost.UI.Login 6 | { 7 | public class LoginService 8 | { 9 | private readonly List _users; 10 | 11 | public LoginService(List users) 12 | { 13 | _users = users; 14 | } 15 | 16 | public bool ValidateCredentials(string username, string password) 17 | { 18 | var user = FindByUsername(username); 19 | if (user != null) 20 | { 21 | return user.Password.Equals(password); 22 | } 23 | return false; 24 | } 25 | 26 | public InMemoryUser FindByUsername(string username) 27 | { 28 | return _users.FirstOrDefault(x=>x.Username.Equals(username, System.StringComparison.OrdinalIgnoreCase)); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Login/LoginViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace IdSvrHost.UI.Login 2 | { 3 | public class LoginViewModel : LoginInputModel 4 | { 5 | public LoginViewModel() 6 | { 7 | } 8 | 9 | public LoginViewModel(LoginInputModel other) 10 | { 11 | Username = other.Username; 12 | Password = other.Password; 13 | RememberLogin = other.RememberLogin; 14 | SignInId = other.SignInId; 15 | } 16 | 17 | public string ErrorMessage { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Login/SignInResult.cs: -------------------------------------------------------------------------------- 1 | using IdentityServer4.Core.Services; 2 | using Microsoft.AspNet.Mvc; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace IdSvrHost.UI.Login 10 | { 11 | public class SignInResult : IActionResult 12 | { 13 | private readonly string _requestId; 14 | 15 | public SignInResult(string requestId) 16 | { 17 | _requestId = requestId; 18 | } 19 | 20 | public async Task ExecuteResultAsync(ActionContext context) 21 | { 22 | var interaction = context.HttpContext.RequestServices.GetRequiredService(); 23 | await interaction.ProcessResponseAsync(_requestId, new IdentityServer4.Core.Models.SignInResponse()); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Login/Views/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IdSvrHost.UI.Login.LoginViewModel 2 | 3 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Logout/LoggedOutViewModel.cs: -------------------------------------------------------------------------------- 1 | using IdentityServer4.Core.Models; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdSvrHost.UI.Logout 8 | { 9 | public class LoggedOutViewModel 10 | { 11 | public LoggedOutViewModel() 12 | { 13 | SignOutIFrameUrls = Enumerable.Empty(); 14 | } 15 | 16 | public ClientReturnInfo ReturnInfo { get; set; } 17 | public string ClientName { get; set; } 18 | 19 | public IEnumerable SignOutIFrameUrls { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Logout/LogoutController.cs: -------------------------------------------------------------------------------- 1 | using IdentityServer4.Core; 2 | using IdentityServer4.Core.Services; 3 | using Microsoft.AspNet.Mvc; 4 | using System.Linq; 5 | using System.Security.Claims; 6 | using System.Threading.Tasks; 7 | 8 | namespace IdSvrHost.UI.Logout 9 | { 10 | public class LogoutController : Controller 11 | { 12 | private readonly SignOutInteraction _signOutInteraction; 13 | 14 | public LogoutController(SignOutInteraction signOutInteraction) 15 | { 16 | _signOutInteraction = signOutInteraction; 17 | } 18 | 19 | [HttpGet(Constants.RoutePaths.Logout, Name = "Logout")] 20 | public IActionResult Index(string id) 21 | { 22 | return View(new LogoutViewModel { SignOutId = id }); 23 | } 24 | 25 | [HttpPost(Constants.RoutePaths.Logout)] 26 | [ValidateAntiForgeryToken] 27 | public async Task Submit(string signOutId) 28 | { 29 | await HttpContext.Authentication.SignOutAsync(Constants.PrimaryAuthenticationType); 30 | 31 | // set this so UI rendering sees an anonymous user 32 | HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity()); 33 | 34 | var vm = new LoggedOutViewModel(); 35 | return View("LoggedOut", vm); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Logout/LogoutViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace IdSvrHost.UI.Logout 7 | { 8 | public class LogoutViewModel 9 | { 10 | public string SignOutId { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Logout/Views/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IdSvrHost.UI.Logout.LogoutViewModel 2 | 3 |
    4 | 7 | 8 |
    9 |
    10 |

    Would you like to logout of IdentityServer?

    11 |
    12 | 13 |
    14 |
    15 | 16 |
    17 |
    18 |
    19 |
    20 |
    21 |
    -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/Logout/Views/LoggedOut.cshtml: -------------------------------------------------------------------------------- 1 | @model IdSvrHost.UI.Logout.LoggedOutViewModel 2 | 3 | 19 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/SharedViews/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model IdSvrHost.UI.Error.ErrorViewModel 2 | 3 | @{ 4 | var error_description = Model?.Error?.ErrorDescription ?? "Sorry, there was an unexpected error."; 5 | var error_code = Model?.Error?.ErrorCode; 6 | var request_id = Model?.Error?.RequestId; 7 | } 8 | 9 |
    10 | 13 | 14 |
    15 |
    16 |
    17 | 18 | 19 | @Model.Error.ErrorCode 20 | 21 | 22 | 23 | @error_description 24 |
    25 | 26 |
    Request Id: @request_id
    27 |
    28 |
    29 |
    30 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/SharedViews/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | IdentityServer4 7 | 8 | 9 | 10 | 11 | 12 | 13 | 42 | 43 |
    44 | @RenderBody() 45 |
    46 | 47 | 48 | 49 | @RenderSection("scripts", required: false) 50 | 51 | 52 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/SharedViews/_ValidationSummary.cshtml: -------------------------------------------------------------------------------- 1 | 
    2 | Error 3 |
    4 |
    5 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/TagHelpers/HideShowTagHelpers.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Razor.TagHelpers; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdSvrHost.UI.TagHelpers 8 | { 9 | [HtmlTargetElement(Attributes = "hide-if")] 10 | public class HideIfTagHelper : TagHelper 11 | { 12 | [HtmlAttributeName("hide-if")] 13 | public bool HideIf { get; set; } 14 | 15 | public override void Process(TagHelperContext context, TagHelperOutput output) 16 | { 17 | if (HideIf) 18 | { 19 | output.SuppressOutput(); 20 | } 21 | } 22 | } 23 | 24 | [HtmlTargetElement(Attributes = "show-if")] 25 | public class ShowIfTagHelper : TagHelper 26 | { 27 | [HtmlAttributeName("show-if")] 28 | public bool ShowIf { get; set; } 29 | 30 | public override void Process(TagHelperContext context, TagHelperOutput output) 31 | { 32 | if (ShowIf == false) 33 | { 34 | output.SuppressOutput(); 35 | } 36 | } 37 | } 38 | 39 | [HtmlTargetElement(Attributes = "hide-if-null")] 40 | public class HideIfNullTagHelper : TagHelper 41 | { 42 | [HtmlAttributeName("hide-if-null")] 43 | public object HideIfNull { get; set; } 44 | 45 | public override void Process(TagHelperContext context, TagHelperOutput output) 46 | { 47 | if (HideIfNull == null) 48 | { 49 | output.SuppressOutput(); 50 | } 51 | } 52 | } 53 | 54 | [HtmlTargetElement(Attributes = "show-if-null")] 55 | public class ShowifNullTagHelper : TagHelper 56 | { 57 | [HtmlAttributeName("show-if-null")] 58 | public object ShowIfNull { get; set; } 59 | 60 | public override void Process(TagHelperContext context, TagHelperOutput output) 61 | { 62 | if (ShowIfNull != null) 63 | { 64 | output.SuppressOutput(); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers" 2 | @addTagHelper "*, IdSvrHost" 3 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/UI/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ApplicationInsights": { 3 | "InstrumentationKey": "" 4 | }, 5 | "Logging": { 6 | "IncludeScopes": false, 7 | "LogLevel": { 8 | "Default": "Verbose", 9 | "System": "Information", 10 | "Microsoft": "Information" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/idsrv4test.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/IdentityServer_aspcore/IdSvrHost/idsrv4test.pfx -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-*", 3 | "compilationOptions": { 4 | "emitEntryPoint": true 5 | }, 6 | 7 | "dependencies": { 8 | "IdentityServer4": "1.0.0-beta1", 9 | "Microsoft.ApplicationInsights.AspNet": "1.0.0-rc1", 10 | "Microsoft.AspNet.Diagnostics": "1.0.0-rc1-final", 11 | "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final", 12 | "Microsoft.AspNet.Mvc": "6.0.0-rc1-final", 13 | "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final", 14 | "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final", 15 | "Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final", 16 | "Microsoft.AspNet.Tooling.Razor": "1.0.0-rc1-final", 17 | "Microsoft.Extensions.Configuration": "1.0.0-rc1-final", 18 | "Microsoft.Extensions.Configuration.FileProviderExtensions": "1.0.0-rc1-final", 19 | "Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final", 20 | "Microsoft.Extensions.Logging": "1.0.0-rc1-final", 21 | "Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final", 22 | "Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final", 23 | "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-rc1-final" 24 | }, 25 | 26 | "commands": { 27 | "web": "Microsoft.AspNet.Server.Kestrel --server.urls=http://localhost:5000" 28 | }, 29 | 30 | "frameworks": { 31 | "dnx451": { 32 | "dependencies": { 33 | 34 | } 35 | }, 36 | "dnxcore50": { } 37 | }, 38 | 39 | "exclude": [ 40 | "wwwroot", 41 | "node_modules" 42 | ], 43 | "publishExclude": [ 44 | "**.user", 45 | "**.vspscc" 46 | ], 47 | "scripts": { 48 | "prepublish": [ "npm install", "bower install", "gulp clean", "gulp min" ] 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin-top: 65px; 3 | } 4 | .navbar-header { 5 | position: relative; 6 | top: -4px; 7 | } 8 | .navbar-brand > .icon-banner { 9 | position: relative; 10 | top: -2px; 11 | display: inline; 12 | } 13 | .icon { 14 | position: relative; 15 | top: -10px; 16 | } 17 | .page-consent .client-logo { 18 | float: left; 19 | } 20 | .page-consent .client-logo img { 21 | width: 80px; 22 | height: 80px; 23 | } 24 | .page-consent .consent-buttons { 25 | margin-top: 25px; 26 | } 27 | .page-consent .consent-form .consent-scopecheck { 28 | display: inline-block; 29 | margin-right: 5px; 30 | } 31 | .page-consent .consent-form .consent-description { 32 | margin-left: 25px; 33 | } 34 | .page-consent .consent-form .consent-description label { 35 | font-weight: normal; 36 | } 37 | .page-consent .consent-form .consent-remember { 38 | padding-left: 16px; 39 | } -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/wwwroot/css/site.less: -------------------------------------------------------------------------------- 1 | body { 2 | margin-top: 65px; 3 | } 4 | 5 | .navbar-header { 6 | position:relative; 7 | top:-4px; 8 | } 9 | 10 | .navbar-brand > .icon-banner { 11 | position:relative; 12 | top:-2px; 13 | display:inline; 14 | } 15 | 16 | .icon { 17 | position:relative; 18 | top:-10px; 19 | } 20 | 21 | .page-consent { 22 | .client-logo { 23 | float: left; 24 | 25 | img { 26 | width: 80px; 27 | height: 80px; 28 | } 29 | } 30 | 31 | .consent-buttons { 32 | margin-top: 25px; 33 | } 34 | 35 | .consent-form { 36 | .consent-scopecheck { 37 | display: inline-block; 38 | margin-right: 5px; 39 | } 40 | 41 | .consent-scopecheck[disabled] { 42 | //visibility:hidden; 43 | } 44 | 45 | .consent-description { 46 | margin-left: 25px; 47 | 48 | label { 49 | font-weight: normal; 50 | } 51 | } 52 | 53 | .consent-remember { 54 | padding-left: 16px; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/wwwroot/css/site.min.css: -------------------------------------------------------------------------------- 1 | body{margin-top:65px;}.navbar-header{position:relative;top:-4px;}.navbar-brand>.icon-banner{position:relative;top:-2px;display:inline;}.icon{position:relative;top:-10px;}.page-consent .client-logo{float:left;}.page-consent .client-logo img{width:80px;height:80px;}.page-consent .consent-buttons{margin-top:25px;}.page-consent .consent-form .consent-scopecheck{display:inline-block;margin-right:5px;}.page-consent .consent-form .consent-description{margin-left:25px;}.page-consent .consent-form .consent-description label{font-weight:normal;}.page-consent .consent-form .consent-remember{padding-left:16px;} -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/IdentityServer_aspcore/IdSvrHost/wwwroot/favicon.ico -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/wwwroot/icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/IdentityServer_aspcore/IdSvrHost/wwwroot/icon.jpg -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/wwwroot/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/IdentityServer_aspcore/IdSvrHost/wwwroot/icon.png -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/IdentityServer_aspcore/IdSvrHost/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/IdentityServer_aspcore/IdSvrHost/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/IdentityServer_aspcore/IdSvrHost/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/IdentityServer_aspcore/IdSvrHost/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /IdentityServer_aspcore/IdSvrHost/wwwroot/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 e 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ServiceStackJWT 2 | [http://estynedwards.com/blog/2016/01/30/ServiceStack-IdentityServer-Angular/](http://estynedwards.com/blog/2016/01/30/ServiceStack-IdentityServer-Angular/) 3 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWT.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Punchard.ServiceStackJWTExample", "Punchard.ServiceStackJWTExample\Punchard.ServiceStackJWTExample.csproj", "{53024FE0-18F4-445D-9A64-8B4C14C9E97C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Punchard.ServiceStackJWTExampleServiceInterface", "Punchard.ServiceStackJWTExample.ServiceInterface\Punchard.ServiceStackJWTExampleServiceInterface.csproj", "{582DFB0F-F84D-4E43-9BCA-2A5A86600B7A}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Punchard.ServiceStackJWTExample.ServiceModel", "Punchard.ServiceStackJWTExample.ServiceModel\Punchard.ServiceStackJWTExample.ServiceModel.csproj", "{08BEF328-AB7D-48D3-800D-48ACC75C7914}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Punchcard.ServiceStackJWT", "Punchcard.ServiceStackJWT\Punchcard.ServiceStackJWT.csproj", "{65782666-7E93-40EA-BDD3-E74C06EF93FA}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Punchard.ServiceStackJWTExample.Tests", "Punchard.ServiceStackJWTExample.Tests\Punchard.ServiceStackJWTExample.Tests.csproj", "{B1665387-EF91-4CA0-82BB-66E5781ED800}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Punchcard.Angular1JWT", "Punchcard.Angular1JWT\Punchcard.Angular1JWT.csproj", "{4CFC2BC0-C0B0-4AC4-8DAE-1FC4C22EFF40}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {53024FE0-18F4-445D-9A64-8B4C14C9E97C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {53024FE0-18F4-445D-9A64-8B4C14C9E97C}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {53024FE0-18F4-445D-9A64-8B4C14C9E97C}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {53024FE0-18F4-445D-9A64-8B4C14C9E97C}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {582DFB0F-F84D-4E43-9BCA-2A5A86600B7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {582DFB0F-F84D-4E43-9BCA-2A5A86600B7A}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {582DFB0F-F84D-4E43-9BCA-2A5A86600B7A}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {582DFB0F-F84D-4E43-9BCA-2A5A86600B7A}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {08BEF328-AB7D-48D3-800D-48ACC75C7914}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {08BEF328-AB7D-48D3-800D-48ACC75C7914}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {08BEF328-AB7D-48D3-800D-48ACC75C7914}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {08BEF328-AB7D-48D3-800D-48ACC75C7914}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {65782666-7E93-40EA-BDD3-E74C06EF93FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {65782666-7E93-40EA-BDD3-E74C06EF93FA}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {65782666-7E93-40EA-BDD3-E74C06EF93FA}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {65782666-7E93-40EA-BDD3-E74C06EF93FA}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {B1665387-EF91-4CA0-82BB-66E5781ED800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {B1665387-EF91-4CA0-82BB-66E5781ED800}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {B1665387-EF91-4CA0-82BB-66E5781ED800}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {B1665387-EF91-4CA0-82BB-66E5781ED800}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {4CFC2BC0-C0B0-4AC4-8DAE-1FC4C22EFF40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {4CFC2BC0-C0B0-4AC4-8DAE-1FC4C22EFF40}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {4CFC2BC0-C0B0-4AC4-8DAE-1FC4C22EFF40}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {4CFC2BC0-C0B0-4AC4-8DAE-1FC4C22EFF40}.Release|Any CPU.Build.0 = Release|Any CPU 48 | EndGlobalSection 49 | GlobalSection(SolutionProperties) = preSolution 50 | HideSolutionNode = FALSE 51 | EndGlobalSection 52 | EndGlobal 53 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.ServiceInterface/MyServices.cs: -------------------------------------------------------------------------------- 1 | using Punchard.ServiceStackJWTExample.ServiceModel; 2 | using ServiceStack; 3 | 4 | namespace Punchard.ServiceStackJWT.ServiceInterface 5 | { 6 | public class MyServices : Service 7 | { 8 | public object Any(Hello request) 9 | { 10 | return new HelloResponse { Result = "Hello, {0}!".Fmt(request.Name) }; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.ServiceInterface/MyServicesAuth.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.Security.Claims; 4 | using System.Web; 5 | using Punchard.ServiceStackJWTExample.ServiceModel; 6 | using ServiceStack; 7 | 8 | namespace Punchard.ServiceStackJWT.ServiceInterface 9 | { 10 | public class MyServicesAuth : Service 11 | { 12 | [Authenticate] 13 | public object Any(HelloAuth request) 14 | 15 | { 16 | Debug.Write(HttpContext.Current.User.Identity.Name); 17 | var x = new HelloResponse { Result = "Hello, {0}!".Fmt(request.Name) }; 18 | var identity = (ClaimsIdentity)HttpContext.Current.User.Identity; 19 | var claims = identity.Claims; 20 | 21 | x.Claims = new List(); 22 | foreach (var claim in claims) 23 | { 24 | x.Claims.Add(claim.Type+" : "+claim.Value); 25 | } 26 | return x; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.ServiceInterface/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Punchard.AngularServiceStack.ServiceInterface")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Punchard.AngularServiceStack.ServiceInterface")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f0103560-0dad-4724-ab5d-b6d4c10665b4")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.ServiceInterface/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.ServiceInterface/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.ServiceModel/Hello.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using ServiceStack; 3 | 4 | namespace Punchard.ServiceStackJWTExample.ServiceModel 5 | { 6 | [Route("/hello/{Name}")] 7 | public class Hello : IReturn 8 | { 9 | public string Name { get; set; } 10 | } 11 | 12 | public class HelloResponse 13 | { 14 | public string Result { get; set; } 15 | public List Claims { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.ServiceModel/HelloAuth.cs: -------------------------------------------------------------------------------- 1 | using ServiceStack; 2 | 3 | namespace Punchard.ServiceStackJWTExample.ServiceModel 4 | { 5 | [Route("/helloAuth/{Name}")] 6 | public class HelloAuth : IReturn 7 | { 8 | public string Name { get; set; } 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.ServiceModel/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Punchard.AngularServiceStack.ServiceModel")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Punchard.AngularServiceStack.ServiceModel")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("173e2443-6adf-4296-b6eb-88157e8d0d8d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.ServiceModel/Punchard.ServiceStackJWTExample.ServiceModel.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {08BEF328-AB7D-48D3-800D-48ACC75C7914} 8 | Library 9 | Properties 10 | Punchard.ServiceStackJWTExample.ServiceModel 11 | Punchard.ServiceStackJWTExample.ServiceModel 12 | v4.5 13 | 512 14 | ..\..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\..\packages\ServiceStack.Common.4.0.52\lib\net40\ServiceStack.Common.dll 37 | True 38 | 39 | 40 | ..\..\packages\ServiceStack.Interfaces.4.0.52\lib\portable-wp80+sl5+net40+win8+monotouch+monoandroid+xamarin.ios10\ServiceStack.Interfaces.dll 41 | True 42 | 43 | 44 | ..\..\packages\ServiceStack.Text.4.0.52\lib\net40\ServiceStack.Text.dll 45 | True 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 76 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.ServiceModel/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Punchard.AngularServiceStack.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Punchard.AngularServiceStack.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("2ef8fa79-f49c-4c48-8201-7eba5d79a38e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.Tests/UnitTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Punchard.ServiceStackJWT.ServiceInterface; 3 | using Punchard.ServiceStackJWTExample.ServiceModel; 4 | using ServiceStack; 5 | using ServiceStack.Testing; 6 | 7 | namespace Punchard.ServiceStackJWTExample.Tests 8 | { 9 | [TestFixture] 10 | public class UnitTests 11 | { 12 | private readonly ServiceStackHost appHost; 13 | 14 | public UnitTests() 15 | { 16 | appHost = new BasicAppHost(typeof(MyServices).Assembly) 17 | { 18 | ConfigureContainer = container => 19 | { 20 | //Add your IoC dependencies here 21 | } 22 | } 23 | .Init(); 24 | } 25 | 26 | [TestFixtureTearDown] 27 | public void TestFixtureTearDown() 28 | { 29 | appHost.Dispose(); 30 | } 31 | 32 | [Test] 33 | public void TestMethod1() 34 | { 35 | var service = appHost.Container.Resolve(); 36 | 37 | var response = (HelloResponse)service.Any(new Hello { Name = "World" }); 38 | 39 | Assert.That(response.Result, Is.EqualTo("Hello, World!")); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.Tests/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample/AppHost.cs: -------------------------------------------------------------------------------- 1 | using Funq; 2 | using Punchard.ServiceStackJWT.ServiceInterface; 3 | using Punchcard.ServiceStackJWT; 4 | using ServiceStack; 5 | using ServiceStack.Auth; 6 | using ServiceStack.Razor; 7 | 8 | namespace Punchard.ServiceStackJWTExample 9 | { 10 | public class AppHost : AppHostBase 11 | { 12 | /// 13 | /// Default constructor. 14 | /// Base constructor requires a name and assembly to locate web service classes. 15 | /// 16 | public AppHost(): base("Punchard.ServiceStackJWT", typeof(MyServices).Assembly) 17 | { 18 | 19 | } 20 | 21 | /// 22 | /// Application specific configuration 23 | /// This method should initialize any IoC resources utilized by your web service classes. 24 | /// 25 | /// 26 | public override void Configure(Container container) 27 | { 28 | //Config examples 29 | this.Plugins.Add(new PostmanFeature()); 30 | this.Plugins.Add(new CorsFeature(allowCredentials:true, allowedHeaders: "Content-Type, Allow, Authorization")); 31 | 32 | this.Plugins.Add(new RazorFormat()); 33 | 34 | //For an access token Audience should be http://{issuer}/resouces 35 | //For an id_token the Audience should the client_id 36 | Plugins.Add(new AuthFeature(() => new AuthUserSession(), 37 | new IAuthProvider[] { 38 | new JsonWebTokenAuthProvider("http://localhost:22530/" + ".well-known/openid-configuration", "http://localhost:22530/resources"), 39 | })); 40 | //setup authentication? 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="Punchard.ServiceStackJWTExample.Global" Language="C#" %> 2 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Punchard.ServiceStackJWTExample 4 | { 5 | public class Global : System.Web.HttpApplication 6 | { 7 | protected void Application_Start(object sender, EventArgs e) 8 | { 9 | new AppHost().Init(); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Punchard.AngularServiceStack")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Punchard.AngularServiceStack")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("6b974b71-9b26-48dc-961f-3071afd7e297")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 |
    10 |
    11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample/default.html: -------------------------------------------------------------------------------- 1 | This project hosts the API and that is all. 2 | -------------------------------------------------------------------------------- /ServiceStack/Punchard.ServiceStackJWTExample/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Visual Studio Project # 2 | ################### 3 | *.user 4 | *.gpState 5 | *.suo 6 | bin 7 | obj 8 | /packages 9 | 10 | # Ignore Node & Bower 11 | ################### 12 | node_modules 13 | /modular/client/build 14 | /modular/build 15 | bower_components 16 | **/test/coverage 17 | /reports 18 | 19 | 20 | # mongo db 21 | ################### 22 | #Don't commit Mongo Database files 23 | *.lock 24 | *.0 25 | *.1 26 | *.ns 27 | journal 28 | 29 | # Ignore Web Storm # 30 | .idea 31 | 32 | # Compiled source # 33 | ################### 34 | *.com 35 | *.class 36 | *.dll 37 | *.exe 38 | *.o 39 | *.so 40 | report/ 41 | 42 | # Packages # 43 | ############ 44 | # it's better to unpack these files and commit the raw source 45 | # git has its own built in compression methods 46 | *.7z 47 | *.dmg 48 | *.gz 49 | *.iso 50 | *.jar 51 | *.rar 52 | *.tar 53 | *.xap 54 | *.zip 55 | 56 | # Logs and databases # 57 | ###################### 58 | *.log 59 | *.sql 60 | *.sqlite 61 | # *.sdf 62 | *.mdf 63 | *.ldf 64 | 65 | # OS generated files # 66 | ###################### 67 | .DS_Store* 68 | ehthumbs.db 69 | Icon? 70 | Thumbs.db 71 | packages 72 | 73 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "excludeFiles": ["node_modules/**", "bower_components/**"], 3 | 4 | 5 | "requireCurlyBraces": [ 6 | "if", 7 | "else", 8 | "for", 9 | "while", 10 | "do", 11 | "try", 12 | "catch" 13 | ], 14 | "requireOperatorBeforeLineBreak": true, 15 | "requireCamelCaseOrUpperCaseIdentifiers": true, 16 | "maximumLineLength": { 17 | "value": 80, 18 | "allowComments": true, 19 | "allowRegex": true 20 | }, 21 | "validateIndentation": 2, 22 | "validateQuoteMarks": "'", 23 | 24 | "disallowMultipleLineStrings": true, 25 | "disallowMixedSpacesAndTabs": true, 26 | "disallowTrailingWhitespace": true, 27 | "disallowSpaceAfterPrefixUnaryOperators": true, 28 | "disallowMultipleVarDecl": null, 29 | 30 | "requireSpaceAfterKeywords": [ 31 | "if", 32 | "else", 33 | "for", 34 | "while", 35 | "do", 36 | "switch", 37 | "return", 38 | "try", 39 | "catch" 40 | ], 41 | "requireSpaceBeforeBinaryOperators": [ 42 | "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", 43 | "&=", "|=", "^=", "+=", 44 | 45 | "+", "-", "*", "/", "%", "<<", ">>", ">>>", "&", 46 | "|", "^", "&&", "||", "===", "==", ">=", 47 | "<=", "<", ">", "!=", "!==" 48 | ], 49 | "requireSpaceAfterBinaryOperators": true, 50 | "requireSpacesInConditionalExpression": true, 51 | "requireSpaceBeforeBlockStatements": true, 52 | "requireLineFeedAtFileEnd": true, 53 | "disallowSpacesInsideObjectBrackets": "all", 54 | "disallowSpacesInsideArrayBrackets": "all", 55 | "disallowSpacesInsideParentheses": true, 56 | 57 | 58 | "validateJSDoc": { 59 | "checkParamNames": true, 60 | "requireParamTypes": true 61 | }, 62 | 63 | "disallowMultipleLineBreaks": true, 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | "requireLineFeedAtFileEnd": null, 72 | "disallowCommaBeforeLineBreak": null, 73 | "disallowDanglingUnderscores": null, 74 | "disallowEmptyBlocks": null, 75 | "disallowMixedSpacesAndTabs": null, 76 | "disallowMultipleLineStrings": null, 77 | "disallowTrailingComma": null, 78 | "disallowTrailingWhitespace": null, 79 | "maximumLineLength": null, 80 | "requireCamelCaseOrUpperCaseIdentifiers": null, 81 | "requireCapitalizedConstructors": null, 82 | "requireCommaBeforeLineBreak": null, 83 | "requireCurlyBraces": null, 84 | "requireDotNotation": null, 85 | "requireMultipleVarDecl": null, 86 | "requireOperatorBeforeLineBreak": null, 87 | "requireParenthesesAroundIIFE": true, 88 | "validateIndentation": 4, 89 | "validateQuoteMarks": null 90 | } -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "es3": false, 7 | "forin": true, 8 | "freeze": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": "nofunc", 12 | "newcap": true, 13 | "noarg": true, 14 | "noempty": true, 15 | "nonbsp": true, 16 | "nonew": true, 17 | "plusplus": false, 18 | "quotmark": "single", 19 | "undef": true, 20 | "unused": false, 21 | "strict": false, 22 | "maxparams": 10, 23 | "maxdepth": 5, 24 | "maxstatements": 40, 25 | "maxcomplexity": 8, 26 | "maxlen": 120, 27 | 28 | "asi": false, 29 | "boss": false, 30 | "debug": false, 31 | "eqnull": true, 32 | "esnext": false, 33 | "evil": false, 34 | "expr": false, 35 | "funcscope": false, 36 | "globalstrict": false, 37 | "iterator": false, 38 | "lastsemic": false, 39 | "laxbreak": false, 40 | "laxcomma": false, 41 | "loopfunc": true, 42 | "maxerr": false, 43 | "moz": false, 44 | "multistr": false, 45 | "notypeof": false, 46 | "proto": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "sub": true, 50 | "supernew": false, 51 | "validthis": false, 52 | "noyield": false, 53 | 54 | "browser": true, 55 | "node": true, 56 | 57 | "globals": { 58 | "angular": false, 59 | "$": false 60 | } 61 | } -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Punchcard.Angular1JWT")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Punchcard.Angular1JWT")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("4cfc2bc0-c0b0-4ac4-8dae-1fc4c22eff40")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AngularJS Modular Demo", 3 | "version": "0.0.1", 4 | "description": "AngularJS Modular Demo", 5 | "authors": [ 6 | "John Papa" 7 | ], 8 | "license": "MIT", 9 | "homepage": "https://github.com/johnpapa/ng-demos", 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "test", 15 | "tests" 16 | ], 17 | "devDependencies": { 18 | "angular-mocks": "~1.2.24" 19 | }, 20 | "dependencies": { 21 | "angular": "~1.2.24", 22 | "toastr": "~2.0.1", 23 | "bootstrap": "~3.1.1", 24 | "moment": "~2.6.0", 25 | "jquery": "~2.1.0", 26 | "angular-route": "~1.2.24", 27 | "angular-animate": "~1.2.24", 28 | "angular-sanitize": "~1.2.24", 29 | "font-awesome": "~4.0.3", 30 | "extras.angular.plus": "~0.9.0", 31 | "oidc-token-manager": "~1.0.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/gulp.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "client": "./src/client/", 3 | "server": "./src/server/", 4 | "api": "/api", 5 | "data": "/../../data/", 6 | "test": "./src/client/test/", 7 | "html": "./src/client/**/*.html", 8 | "htmltemplates": "./src/client/app/**/*.html", 9 | "vendorjs": [ 10 | "./bower_components/jquery/dist/jquery.min.js", 11 | "./bower_components/angular/angular.min.js", 12 | "./bower_components/angular-animate/angular-animate.min.js", 13 | "./bower_components/angular-route/angular-route.min.js", 14 | "./bower_components/angular-sanitize/angular-sanitize.min.js", 15 | "./bower_components/bootstrap/dist/js/bootstrap.min.js", 16 | "./bower_components/toastr/toastr.min.js", 17 | "./bower_components/moment/min/moment.min.js", 18 | "./bower_components/extras.angular.plus/ngplus-overlay.js" 19 | ], 20 | "vendorcss": [ 21 | "./bower_components/bootstrap/dist/css/bootstrap.min.css", 22 | "./bower_components/font-awesome/css/font-awesome.min.css", 23 | "./bower_components/toastr/toastr.css" 24 | ], 25 | "css": [ 26 | "./src/client/content/customtheme.css", 27 | "./src/client/content/styles.css" 28 | ], 29 | "js": [ 30 | "./src/client/app/**/*module*.js", 31 | "./src/client/app/**/*.js", 32 | "!./src/client/app/**/*-spaghetti.js" 33 | ], 34 | "specs": [ 35 | "./src/client/test/specs/*.spec.js" 36 | ], 37 | "nodejs": [ 38 | "./src/server/**/*.js" 39 | ], 40 | "fonts": [ 41 | "./bower_components/font-awesome/fonts/**/*.*" 42 | ], 43 | "images": [ 44 | "./src/client/content/images/**/*" 45 | ], 46 | "report": "./report/", 47 | "build": "./build/" 48 | } -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/gulp/commentWrapper.js: -------------------------------------------------------------------------------- 1 | (function (commentWrapper) { 2 | 3 | commentWrapper.wrap = wrap; 4 | 5 | function wrap(comments) { 6 | var output = '/*\n'; 7 | comments.forEach(function (line) { 8 | output = output + '* ' + line + '\n'; 9 | }); 10 | output = output + '*/\n'; 11 | return output; 12 | } 13 | 14 | })(module.exports) -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/gulp/common.js: -------------------------------------------------------------------------------- 1 | (function (common) { 2 | var commentWrapper = require('./commentWrapper.js'); 3 | 4 | common.createComments = createComments; 5 | common.formatPercent = formatPercent; 6 | common.bytediffFormatter = bytediffFormatter; 7 | 8 | function bytediffFormatter(data) { 9 | var difference = (data.savings > 0) ? ' smaller.' : ' larger.'; 10 | return data.fileName + ' went from ' 11 | + (data.startSize / 1000).toFixed(2) + ' kB to ' + (data.endSize / 1000).toFixed(2) + ' kB' 12 | + ' and is ' + common.formatPercent(1-data.percent, 2) + '%' + difference; 13 | } 14 | 15 | // Create standard comments header for minified files 16 | function createComments(gutil) { 17 | var comments = [ 18 | 'John Papa', 19 | 'Copyright 2014', 20 | 'MIT License', 21 | 'Compiled on ' + gutil.date('mmm d, yyyy h:MM:ss TT Z') 22 | ]; 23 | return commentWrapper.wrap(comments); 24 | } 25 | 26 | function formatPercent(num, precision){ 27 | return (num*100).toFixed(precision); 28 | } 29 | 30 | })(module.exports) -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/gulp/copyright.js: -------------------------------------------------------------------------------- 1 | //     .pipe(plug.header(fs.readFileSync('./gulp/copyright.js'), {version: pkg.version})) 2 | 3 | /** 4 | * @author John Papa 5 | * @version: 6 | * <%= version %> 7 | * @links 8 | * http://github.com/johnpapa/ng-demos 9 | * http://twitter.com/johnpapa 10 | * http://johnpapa.net 11 | * @source 12 | * http://github.com/johnpapa/ng-demos 13 | * @license: 14 | * MIT License http://www.opensource.org/licenses/mit-license.php 15 | */ -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/iisnode.yml: -------------------------------------------------------------------------------- 1 | # For documentation see https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/iisnode.yml 2 | 3 | loggingEnabled: true 4 | debuggingEnabled: true 5 | devErrorsEnabled: true 6 | node_env: development 7 | nodeProcessCountPerApplication: 1 8 | maxConcurrentRequestsPerProcess: 1024 9 | maxNamedPipeConnectionRetry: 24 10 | namedPipeConnectionRetryDelay: 250 11 | maxNamedPipeConnectionPoolSize: 512 12 | maxNamedPipePooledConnectionAge: 30000 13 | asyncCompletionThreadCount: 0 14 | initialRequestBufferSize: 4096 15 | maxRequestBufferSize: 65536 16 | watchedFiles: *.js;iisnode.yml;node_modules\* 17 | uncFileChangesPollingInterval: 5000 18 | gracefulShutdownTimeout: 60000 19 | logDirectoryNameSuffix: logs 20 | debuggerPortRange: 5058-6058 21 | debuggerPathSegment: debug 22 | maxLogFileSizeInKB: 128 23 | appendToExistingLog: false 24 | logFileFlushInterval: 5000 25 | flushResponse: false 26 | enableXFF: false 27 | promoteServerVars: -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Sun Jul 13 2014 09:06:13 GMT-0400 (EDT) 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: './', 9 | 10 | // frameworks to use 11 | // some available frameworks: https://npmjs.org/browse/keyword/karma-adapter 12 | frameworks: ['mocha', 'chai', 'sinon', 'chai-sinon'], 13 | 14 | // list of files / patterns to load in the browser 15 | files: [ 16 | './src/client/test/lib/bindPolyfill.js', 17 | 18 | './node_modules/ng-midway-tester/src/ngMidwayTester.js', 19 | 20 | './bower_components/jquery/dist/jquery.js', 21 | './bower_components/angular/angular.js', 22 | './bower_components/angular-mocks/angular-mocks.js', 23 | './bower_components/angular-animate/angular-animate.js', 24 | './bower_components/angular-route/angular-route.js', 25 | './bower_components/angular-sanitize/angular-sanitize.js', 26 | './bower_components/bootstrap/dist/js/bootstrap.js', 27 | './bower_components/toastr/toastr.js', 28 | './bower_components/moment/moment.js', 29 | './bower_components/extras.angular.plus/ngplus-overlay.js', 30 | 31 | './src/client/app/app.module.js', 32 | './src/client/app/**/*.module.js', 33 | './src/client/app/**/*.js', 34 | 35 | /* MOCHA */ 36 | './src/client/test/lib/specHelper.js', 37 | './src/client/test/lib/mockData.js', 38 | 39 | './src/client/test/basics/**/*.src.js', 40 | './src/client/test/basics/**/*.spec.js', 41 | 42 | // all specs ... comment out during early test training 43 | './src/client/test/**/*.spec.js' 44 | 45 | ], 46 | 47 | // list of files to exclude 48 | exclude: [ 49 | // Excluding midway tests for now; comment this line out when you want to run them 50 | './src/client/test/midway/**/*.spec.js', 51 | './src/client/app/**/*spaghetti.js' 52 | ], 53 | 54 | proxies: { 55 | '/': 'http://localhost:8888/' 56 | }, 57 | 58 | // preprocess matching files before serving them to the browser 59 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 60 | preprocessors: { 61 | 'src/client/app/**/*.js': 'coverage' 62 | }, 63 | 64 | // test results reporter to use 65 | // possible values: 'dots', 'progress', 'coverage' 66 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 67 | reporters: ['progress'], 68 | 69 | coverageReporter: { 70 | type: 'lcov', 71 | dir: 'test/coverage' 72 | }, 73 | 74 | // web server port 75 | port: 9876, 76 | 77 | // enable / disable colors in the output (reporters and logs) 78 | colors: true, 79 | 80 | // level of logging 81 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 82 | logLevel: config.LOG_INFO, 83 | 84 | // enable / disable watching file and executing tests whenever any file changes 85 | autoWatch: true, 86 | 87 | // start these browsers 88 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 89 | // browsers: ['Chrome', 'ChromeCanary', 'FirefoxAurora', 'Safari', 'PhantomJS'], 90 | browsers: ['PhantomJS'], 91 | 92 | // Continuous Integration mode 93 | // if true, Karma captures browsers, runs the tests and exits 94 | singleRun: false 95 | }); 96 | }; 97 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AngularJS-Modular-Demo", 3 | "version": "0.0.1", 4 | "description": "AngularJS Modular Demo", 5 | "authors": [ 6 | "John Papa" 7 | ], 8 | "license": "MIT", 9 | "homepage": "https://github.com/johnpapa/ng-demos", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/johnpapa/ng-demos.git" 13 | }, 14 | "scripts": { 15 | "init": "npm install", 16 | "install": "bower install", 17 | "start": "node src/server/app.js", 18 | "test": "gulp test" 19 | }, 20 | "dependencies": { 21 | "body-parser": "^1.8.2", 22 | "compression": "^1.1.0", 23 | "cors": "^2.2.0", 24 | "express": "^4.9.3", 25 | "method-override": "^1.0.0", 26 | "morgan": "^1.1.1", 27 | "serve-favicon": "^2.0.1" 28 | }, 29 | "devDependencies": { 30 | "browser-sync": "^1.6.5", 31 | "chai": "^1.9.1", 32 | "chai-as-promised": "^4.1.1", 33 | "chalk": "^0.5.1", 34 | "dateformat": "^1.0.8-1.2.3", 35 | "debug": "^0.8.1", 36 | "del": "^0.1.3", 37 | "glob": "^4.0.5", 38 | "gulp": "^3.8.10", 39 | "gulp-angular-templatecache": "^1.3.0", 40 | "gulp-autoprefixer": "0.0.10", 41 | "gulp-bytediff": "^0.2.0", 42 | "gulp-cache": "^0.2.0", 43 | "gulp-concat": "^2.3.3", 44 | "gulp-filter": "^1.0.2", 45 | "gulp-imagemin": "^1.0.1", 46 | "gulp-inject": "^1.0.1", 47 | "gulp-jscs": "^1.1.2", 48 | "gulp-jshint": "^1.7.1", 49 | "gulp-load-plugins": "^0.6.0", 50 | "gulp-load-utils": "^0.0.4", 51 | "gulp-minify-css": "^0.3.7", 52 | "gulp-minify-html": "^0.1.4", 53 | "gulp-ng-annotate": "^0.3.2", 54 | "gulp-nodemon": "^1.0.4", 55 | "gulp-notify": "^1.6.0", 56 | "gulp-plumber": "^0.6.4", 57 | "gulp-rev": "^1.1.0", 58 | "gulp-rev-replace": "^0.3.1", 59 | "gulp-sourcemaps": "^1.1.5", 60 | "gulp-task-listing": "^0.3.0", 61 | "gulp-uglify": "^1.0.1", 62 | "gulp-util": "^3.0.1", 63 | "jshint-stylish": "^0.4.0", 64 | "karma": "^0.12.23", 65 | "karma-chai": "^0.1.0", 66 | "karma-chai-sinon": "^0.1.3", 67 | "karma-chrome-launcher": "^0.1.4", 68 | "karma-coverage": "^0.2.4", 69 | "karma-firefox-launcher": "^0.1.3", 70 | "karma-growl-reporter": "^0.1.1", 71 | "karma-mocha": "^0.1.4", 72 | "karma-phantomjs-launcher": "^0.1.4", 73 | "karma-safari-launcher": "^0.1.1", 74 | "karma-sinon": "^1.0.3", 75 | "merge-stream": "^0.1.5", 76 | "minimist": "^1.1.0", 77 | "mocha": "^1.20.1", 78 | "ng-midway-tester": "^2.0.5", 79 | "phantomjs": "^1.9.7-14", 80 | "plato": "^1.2.2", 81 | "q": "^1.0.1", 82 | "sinon": "^1.10.3", 83 | "sinon-chai": "^2.5.0" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/Claims/claims.html: -------------------------------------------------------------------------------- 1 | 
    2 |
    3 |
    4 |
    5 |
    6 |
    7 | 8 |
    9 |
    10 |
    11 |
    Access Token
    12 |
    13 |
    {{vm.access_token_header|json}}
    14 |
    {{vm.access_token_content|json}}
    15 |
    {{vm.access_token}}
    16 |
    17 |
    18 |
    19 |
    20 |
    21 |
    ID Token Contents
    22 |
    23 |
    {{vm.id_content|json}}
    24 |
    {{vm.id_token}}
    25 |
    26 |
    27 |
    28 |
    29 |
    30 |
    Ajax Result
    31 |
    32 |
    {{c}}
    33 |
    34 |
    35 |
    36 |
    37 |
    38 |
    39 |
    40 |
    41 |
    42 |
    43 |
    44 |
    45 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/Claims/claims.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.claims') 6 | .controller('Claims', Claims); 7 | 8 | /* @ngInject */ 9 | function Claims(dataservice, logger, authService) { 10 | /*jshint validthis: true */ 11 | var vm = this; 12 | vm.claims = []; 13 | vm.title = 'Claims'; 14 | 15 | activate(); 16 | vm.access_token = authService.OidcTokenManager().access_token; 17 | vm.id_token = authService.OidcTokenManager().id_token; 18 | vm.id_content = authService.OidcTokenManager().profile; 19 | parseAccessToken(authService.OidcTokenManager().access_token); 20 | function activate() { 21 | // Using a resolver on all routes or dataservice.ready in every controller 22 | // var promises = [getAvengers()]; 23 | // return dataservice.ready(promises).then(function(){ 24 | return getClaims().then(function() { 25 | logger.info('Activated Claims View'); 26 | 27 | }); 28 | 29 | } 30 | 31 | function getClaims() { 32 | return dataservice.getHelloAuth().then(function(data) { 33 | vm.claims = data.Claims; 34 | return vm.claims; 35 | }); 36 | } 37 | 38 | function parseAccessToken(token) { 39 | var parts = token.split("."); 40 | vm.access_token_header = JSON.parse(decode(parts[0]).result); 41 | vm.access_token_content = JSON.parse(decode(parts[1]).result); 42 | 43 | } 44 | 45 | function url_base64_decode(str) { 46 | var output = str.replace(/-/g, '+').replace(/_/g, '/'); 47 | switch (output.length % 4) { 48 | case 0: 49 | break; 50 | case 2: 51 | output += '=='; 52 | break; 53 | case 3: 54 | output += '='; 55 | break; 56 | default: 57 | throw 'Illegal base64url string!'; 58 | } 59 | var result = window.atob(output); //polifyll https://github.com/davidchambers/Base64.js 60 | try { 61 | return decodeURIComponent(escape(result)); 62 | } catch (err) { 63 | return result; 64 | } 65 | } 66 | 67 | function decode(base64json) { 68 | var json = null, error = null; 69 | try { 70 | json = url_base64_decode(base64json); 71 | json = JSON.stringify(JSON.parse(json), undefined, 2); 72 | } catch (e) { 73 | error = e; 74 | } 75 | return { result: json, error: error }; 76 | }; 77 | } 78 | })(); 79 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/Claims/claims.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.claims', []); 5 | })(); 6 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/Claims/config.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.claims') 6 | .run(appRun); 7 | 8 | // appRun.$inject = ['routehelper'] 9 | 10 | /* @ngInject */ 11 | function appRun(routehelper) { 12 | routehelper.configureRoutes(getRoutes()); 13 | } 14 | 15 | function getRoutes() { 16 | return [ 17 | { 18 | url: '/claims', 19 | config: { 20 | templateUrl: 'app/claims/claims.html', 21 | controller: 'Claims', 22 | controllerAs: 'vm', 23 | title: 'claims', 24 | settings: { 25 | nav: 2, 26 | content: ' Claims' 27 | } 28 | } 29 | } 30 | ]; 31 | } 32 | })(); 33 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/app.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app', [ 5 | /* 6 | * Order is not important. Angular makes a 7 | * pass to register all of the modules listed 8 | * and then when app.dashboard tries to use app.data, 9 | * its components are available. 10 | */ 11 | 12 | /* 13 | * Everybody has access to these. 14 | * We could place these under every feature area, 15 | * but this is easier to maintain. 16 | */ 17 | 'app.core', 18 | 'app.widgets', 19 | 20 | /* 21 | * Feature areas 22 | */ 23 | 24 | 'app.dashboard', 25 | 'app.layout', 26 | 'app.claims' 27 | ]); 28 | 29 | })(); 30 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/blocks/exception/exception-handler.provider.js: -------------------------------------------------------------------------------- 1 | // Include in index.html so that app level exceptions are handled. 2 | // Exclude from testRunner.html which should run exactly what it wants to run 3 | (function() { 4 | 'use strict'; 5 | 6 | angular 7 | .module('blocks.exception') 8 | .provider('exceptionHandler', exceptionHandlerProvider) 9 | .config(config); 10 | 11 | /** 12 | * Must configure the exception handling 13 | * @return {[type]} 14 | */ 15 | function exceptionHandlerProvider() { 16 | /* jshint validthis:true */ 17 | this.config = { 18 | appErrorPrefix: undefined 19 | }; 20 | 21 | this.configure = function (appErrorPrefix) { 22 | this.config.appErrorPrefix = appErrorPrefix; 23 | }; 24 | 25 | this.$get = function() { 26 | return {config: this.config}; 27 | }; 28 | } 29 | 30 | /** 31 | * Configure by setting an optional string value for appErrorPrefix. 32 | * Accessible via config.appErrorPrefix (via config value). 33 | * @param {[type]} $provide 34 | * @return {[type]} 35 | * @ngInject 36 | */ 37 | function config($provide) { 38 | $provide.decorator('$exceptionHandler', extendExceptionHandler); 39 | } 40 | 41 | /** 42 | * Extend the $exceptionHandler service to also display a toast. 43 | * @param {Object} $delegate 44 | * @param {Object} exceptionHandler 45 | * @param {Object} logger 46 | * @return {Function} the decorated $exceptionHandler service 47 | */ 48 | function extendExceptionHandler($delegate, exceptionHandler, logger) { 49 | return function(exception, cause) { 50 | var appErrorPrefix = exceptionHandler.config.appErrorPrefix || ''; 51 | var errorData = {exception: exception, cause: cause}; 52 | exception.message = appErrorPrefix + exception.message; 53 | $delegate(exception, cause); 54 | /** 55 | * Could add the error to a service's collection, 56 | * add errors to $rootScope, log errors to remote web server, 57 | * or log locally. Or throw hard. It is entirely up to you. 58 | * throw exception; 59 | * 60 | * @example 61 | * throw { message: 'error message we added' }; 62 | */ 63 | logger.error(exception.message, errorData); 64 | }; 65 | } 66 | })(); 67 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/blocks/exception/exception.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('blocks.exception') 6 | .factory('exception', exception); 7 | 8 | /* @ngInject */ 9 | function exception(logger) { 10 | var service = { 11 | catcher: catcher 12 | }; 13 | return service; 14 | 15 | function catcher(message) { 16 | return function(reason) { 17 | logger.error(message, reason); 18 | }; 19 | } 20 | } 21 | })(); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/blocks/exception/exception.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('blocks.exception', ['blocks.logger']); 5 | })(); 6 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/blocks/logger/logger.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('blocks.logger') 6 | .factory('logger', logger); 7 | 8 | logger.$inject = ['$log', 'toastr']; 9 | 10 | function logger($log, toastr) { 11 | var service = { 12 | showToasts: true, 13 | 14 | error : error, 15 | info : info, 16 | success : success, 17 | warning : warning, 18 | 19 | // straight to console; bypass toastr 20 | log : $log.log 21 | }; 22 | 23 | return service; 24 | ///////////////////// 25 | 26 | function error(message, data, title) { 27 | toastr.error(message, title); 28 | $log.error('Error: ' + message, data); 29 | } 30 | 31 | function info(message, data, title) { 32 | toastr.info(message, title); 33 | $log.info('Info: ' + message, data); 34 | } 35 | 36 | function success(message, data, title) { 37 | toastr.success(message, title); 38 | $log.info('Success: ' + message, data); 39 | } 40 | 41 | function warning(message, data, title) { 42 | toastr.warning(message, title); 43 | $log.warn('Warning: ' + message, data); 44 | } 45 | } 46 | }()); 47 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/blocks/logger/logger.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('blocks.logger', []); 5 | })(); 6 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/blocks/router/routehelper.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('blocks.router') 6 | .provider('routehelperConfig', routehelperConfig) 7 | .factory('routehelper', routehelper); 8 | 9 | routehelper.$inject = ['$location', '$rootScope', '$route', 'logger', 'routehelperConfig']; 10 | 11 | // Must configure via the routehelperConfigProvider 12 | function routehelperConfig() { 13 | /* jshint validthis:true */ 14 | this.config = { 15 | // These are the properties we need to set 16 | // $routeProvider: undefined 17 | // docTitle: '' 18 | // resolveAlways: {ready: function(){ } } 19 | }; 20 | 21 | this.$get = function() { 22 | return { 23 | config: this.config 24 | }; 25 | }; 26 | } 27 | 28 | function routehelper($location, $rootScope, $route, logger, routehelperConfig) { 29 | var handlingRouteChangeError = false; 30 | var routeCounts = { 31 | errors: 0, 32 | changes: 0 33 | }; 34 | var routes = []; 35 | var $routeProvider = routehelperConfig.config.$routeProvider; 36 | 37 | var service = { 38 | configureRoutes: configureRoutes, 39 | getRoutes: getRoutes, 40 | routeCounts: routeCounts 41 | }; 42 | 43 | init(); 44 | 45 | return service; 46 | /////////////// 47 | 48 | function configureRoutes(routes) { 49 | routes.forEach(function(route) { 50 | route.config.resolve = 51 | angular.extend(route.config.resolve || {}, routehelperConfig.config.resolveAlways); 52 | $routeProvider.when(route.url, route.config); 53 | }); 54 | $routeProvider.otherwise({redirectTo: '/'}); 55 | } 56 | 57 | function handleRoutingErrors() { 58 | // Route cancellation: 59 | // On routing error, go to the dashboard. 60 | // Provide an exit clause if it tries to do it twice. 61 | $rootScope.$on('$routeChangeError', 62 | function(event, current, previous, rejection) { 63 | if (handlingRouteChangeError) { 64 | return; 65 | } 66 | routeCounts.errors++; 67 | handlingRouteChangeError = true; 68 | var destination = (current && (current.title || current.name || current.loadedTemplateUrl)) || 69 | 'unknown target'; 70 | var msg = 'Error routing to ' + destination + '. ' + (rejection.msg || ''); 71 | logger.warning(msg, [current]); 72 | $location.path('/'); 73 | } 74 | ); 75 | } 76 | 77 | function init() { 78 | handleRoutingErrors(); 79 | updateDocTitle(); 80 | } 81 | 82 | function getRoutes() { 83 | for (var prop in $route.routes) { 84 | if ($route.routes.hasOwnProperty(prop)) { 85 | var route = $route.routes[prop]; 86 | var isRoute = !!route.title; 87 | if (isRoute) { 88 | routes.push(route); 89 | } 90 | } 91 | } 92 | return routes; 93 | } 94 | 95 | function updateDocTitle() { 96 | $rootScope.$on('$routeChangeSuccess', 97 | function(event, current, previous) { 98 | routeCounts.changes++; 99 | handlingRouteChangeError = false; 100 | var title = routehelperConfig.config.docTitle + ' ' + (current.title || ''); 101 | $rootScope.title = title; // data bind to 102 | } 103 | ); 104 | } 105 | } 106 | })(); 107 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/blocks/router/router.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('blocks.router', [ 5 | 'ngRoute', 6 | 'blocks.logger' 7 | ]); 8 | })(); 9 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/core/AuthService.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core') 6 | .factory('authService', authService); 7 | 8 | /* @ngInject */ 9 | function authService() { 10 | 11 | var config = { 12 | authority: "http://localhost:22530/", 13 | client_id: "js_oidc", 14 | redirect_uri: window.location.protocol + "//" + window.location.host + "/callback.html", 15 | post_logout_redirect_uri: window.location.protocol + "//" + window.location.host + "/index.html", 16 | 17 | // these two will be done dynamically from the buttons clicked, but are 18 | // needed if you want to use the silent_renew 19 | response_type: "id_token token", 20 | scope: "openid profile email api1 api2", 21 | 22 | // this will toggle if profile endpoint is used 23 | load_user_profile: true, 24 | 25 | // silent renew will get a new access_token via an iframe 26 | // just prior to the old access_token expiring (60 seconds prior) 27 | silent_redirect_uri: window.location.protocol + "//" + window.location.host + "/silent_renew.html", 28 | silent_renew: false, 29 | 30 | // this will allow all the OIDC protocol claims to be visible in the window. normally a client app 31 | // wouldn't care about them or want them taking up space 32 | filter_protocol_claims: false 33 | }; 34 | 35 | var mgr = new OidcTokenManager(config); 36 | 37 | return { OidcTokenManager: function() { return mgr; } } 38 | 39 | } 40 | 41 | 42 | angular 43 | .module('app.core') 44 | .factory('oidcInterceptor', oidcInterceptor); 45 | /* @ngInject */ 46 | function oidcInterceptor(globalConfig, authService) { 47 | 48 | 49 | 50 | return { 51 | 'request': function (config) { 52 | if (config.url.indexOf(globalConfig.baseUrl) === 0) { 53 | config.headers.Authorization = 'Bearer ' + authService.OidcTokenManager().access_token; 54 | } 55 | return config; 56 | } 57 | 58 | } 59 | 60 | } 61 | })(); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/core/config.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | var core = angular.module('app.core'); 5 | 6 | core.config(toastrConfig); 7 | 8 | /* @ngInject */ 9 | function toastrConfig(toastr) { 10 | toastr.options.timeOut = 4000; 11 | toastr.options.positionClass = 'toast-bottom-right'; 12 | } 13 | 14 | var config = { 15 | appErrorPrefix: '[NG-Modular Error] ', //Configure the exceptionHandler decorator 16 | appTitle: 'Angular Modular Demo', 17 | version: '1.0.0' 18 | }; 19 | 20 | core.value('config', config); 21 | 22 | core.config(configure); 23 | 24 | /* @ngInject */ 25 | function configure($logProvider, $routeProvider, routehelperConfigProvider, exceptionHandlerProvider, $httpProvider) { 26 | // turn debugging off/on (no info or warn) 27 | if ($logProvider.debugEnabled) { 28 | $logProvider.debugEnabled(true); 29 | } 30 | 31 | // Configure the common route provider 32 | routehelperConfigProvider.config.$routeProvider = $routeProvider; 33 | routehelperConfigProvider.config.docTitle = 'NG-Modular: '; 34 | var resolveAlways = { /* @ngInject */ 35 | ready: function(dataservice) { 36 | return dataservice.ready(); 37 | } 38 | // ready: ['dataservice', function (dataservice) { 39 | // return dataservice.ready(); 40 | // }] 41 | }; 42 | routehelperConfigProvider.config.resolveAlways = resolveAlways; 43 | $httpProvider.interceptors.push('oidcInterceptor'); 44 | // Configure the common exception handler 45 | exceptionHandlerProvider.configure(config.appErrorPrefix); 46 | } 47 | })(); 48 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/core/constants.js: -------------------------------------------------------------------------------- 1 | /* global toastr:false, moment:false */ 2 | (function() { 3 | 'use strict'; 4 | 5 | angular 6 | .module('app.core') 7 | .constant('toastr', toastr) 8 | .constant('moment', moment) 9 | .constant('globalConfig', { baseUrl: 'http://localhost:14096/' }); 10 | })(); 11 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/core/core.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.core', [ 5 | /* 6 | * Angular modules 7 | */ 8 | 'ngAnimate', 'ngRoute', 'ngSanitize', 9 | /* 10 | * Our reusable cross app code modules 11 | */ 12 | 'blocks.exception', 'blocks.logger', 'blocks.router', 13 | /* 14 | * 3rd Party modules 15 | */ 16 | 'ngplus' 17 | ]); 18 | })(); 19 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/core/dataservice.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core') 6 | .factory('dataservice', dataservice); 7 | 8 | /* @ngInject */ 9 | function dataservice($http, $location, $q, exception, logger, globalConfig) { 10 | var isPrimed = false; 11 | var primePromise; 12 | 13 | 14 | var service = { 15 | getAvengersCast: getAvengersCast, 16 | getAvengerCount: getAvengerCount, 17 | getAvengers: getAvengers, 18 | getHello: getHello, 19 | getHelloAuth: getHelloAuth, 20 | ready: ready 21 | }; 22 | 23 | return service; 24 | 25 | function getHello() { 26 | return $http.get(globalConfig.baseUrl + 'hello/bob') 27 | .then(getHelloComplete) 28 | .catch(function (message) { 29 | exception.catcher('XHR Failed for getHello')(message); 30 | $location.url('/'); 31 | }); 32 | 33 | function getHelloComplete(data, status, headers, config) { 34 | return data.data; 35 | } 36 | } 37 | function getHelloAuth() { 38 | return $http.get(globalConfig.baseUrl + 'helloAuth/bob') 39 | .then(getHelloComplete) 40 | .catch(function (message) { 41 | exception.catcher('XHR Failed for getHello')(message); 42 | $location.url('/'); 43 | }); 44 | 45 | function getHelloComplete(data, status, headers, config) { 46 | return data.data; 47 | } 48 | } 49 | 50 | function getAvengers() { 51 | return $http.get('/api/maa') 52 | .then(getAvengersComplete) 53 | .catch(function(message) { 54 | exception.catcher('XHR Failed for getAvengers')(message); 55 | $location.url('/'); 56 | }); 57 | 58 | function getAvengersComplete(data, status, headers, config) { 59 | return data.data[0].data.results; 60 | } 61 | } 62 | 63 | function getAvengerCount() { 64 | var count = 0; 65 | return getAvengersCast() 66 | .then(getAvengersCastComplete) 67 | .catch(exception.catcher('XHR Failed for getAvengerCount')); 68 | 69 | function getAvengersCastComplete (data) { 70 | count = data.length; 71 | return $q.when(count); 72 | } 73 | } 74 | 75 | function getAvengersCast() { 76 | var cast = [ 77 | {name: 'Robert Downey Jr.', character: 'Tony Stark / Iron Man'}, 78 | {name: 'Chris Hemsworth', character: 'Thor'}, 79 | {name: 'Chris Evans', character: 'Steve Rogers / Captain America'}, 80 | {name: 'Mark Ruffalo', character: 'Bruce Banner / The Hulk'}, 81 | {name: 'Scarlett Johansson', character: 'Natasha Romanoff / Black Widow'}, 82 | {name: 'Jeremy Renner', character: 'Clint Barton / Hawkeye'}, 83 | {name: 'Gwyneth Paltrow', character: 'Pepper Potts'}, 84 | {name: 'Samuel L. Jackson', character: 'Nick Fury'}, 85 | {name: 'Paul Bettany', character: 'Jarvis'}, 86 | {name: 'Tom Hiddleston', character: 'Loki'}, 87 | {name: 'Clark Gregg', character: 'Agent Phil Coulson'} 88 | ]; 89 | return $q.when(cast); 90 | } 91 | 92 | function prime() { 93 | // This function can only be called once. 94 | if (primePromise) { 95 | return primePromise; 96 | } 97 | 98 | primePromise = $q.when(true).then(success); 99 | return primePromise; 100 | 101 | function success() { 102 | isPrimed = true; 103 | logger.info('Primed data'); 104 | } 105 | } 106 | 107 | function ready(nextPromises) { 108 | var readyPromise = primePromise || prime(); 109 | 110 | return readyPromise 111 | .then(function() { return $q.all(nextPromises); }) 112 | .catch(exception.catcher('"ready" function failed')); 113 | } 114 | function getHelloResponse() { 115 | $http.get('') 116 | } 117 | } 118 | })(); 119 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/dashboard/config.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.dashboard') 6 | .run(appRun); 7 | 8 | // appRun.$inject = ['routehelper']; 9 | 10 | /* @ngInject */ 11 | function appRun(routehelper) { 12 | routehelper.configureRoutes(getRoutes()); 13 | } 14 | 15 | function getRoutes() { 16 | return [ 17 | { 18 | url: '/', 19 | config: { 20 | templateUrl: 'app/dashboard/dashboard.html', 21 | controller: 'Dashboard', 22 | controllerAs: 'vm', 23 | title: 'dashboard', 24 | settings: { 25 | nav: 1, 26 | content: '<i class="fa fa-dashboard"></i> Dashboard' 27 | } 28 | } 29 | } 30 | ]; 31 | } 32 | })(); 33 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/dashboard/dashboard.html: -------------------------------------------------------------------------------- 1 | <section id="dashboard-view" class="mainbar"> 2 | <section class="matter"> 3 | <div class="container"> 4 | <div class="row"> 5 | <div class="col-md-12"> 6 | This is the dashboard 7 | </div> 8 | </div> 9 | 10 | </div> 11 | </section> 12 | </section> -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/dashboard/dashboard.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.dashboard') 6 | .controller('Dashboard', Dashboard); 7 | 8 | Dashboard.$inject = ['$q', 'dataservice', 'logger']; 9 | 10 | function Dashboard($q, dataservice, logger) { 11 | 12 | /*jshint validthis: true */ 13 | var vm = this; 14 | 15 | 16 | vm.title = 'Dashboard'; 17 | 18 | init(); 19 | 20 | function init() { 21 | var promises = []; 22 | // 23 | return $q.all(promises).then(function() { 24 | logger.info('Activated Dashboard View'); 25 | }); 26 | } 27 | 28 | 29 | } 30 | })(); 31 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/dashboard/dashboard.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.dashboard', []); 5 | })(); 6 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/layout/layout.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.layout', []); 5 | })(); 6 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/layout/shell.html: -------------------------------------------------------------------------------- 1 | <div data-ng-controller="Shell as vm"> 2 | <div id="splash-page" data-ng-show="vm.showSplash" class="dissolve-animation"> 3 | <div class="page-splash"> 4 | <div class="page-splash-message"> 5 | Modular Demo 6 | </div> 7 | </div> 8 | </div> 9 | 10 | <header class="clearfix"> 11 | <div data-ng-include="'app/layout/topnav.html'"></div> 12 | </header> 13 | <section id="content" class="content"> 14 | <div data-ng-include="'app/layout/sidebar.html'"></div> 15 | 16 | <div data-ng-view class="shuffle-animation"></div> 17 | 18 | <div ngplus-overlay 19 | ngplus-overlay-delay-in="50" 20 | ngplus-overlay-delay-out="700" 21 | ngplus-overlay-animation="dissolve-animation"> 22 | <img src="../../content/images/busy.gif"/> 23 | 24 | <div class="page-spinner-message overlay-message">{{vm.busyMessage}}</div> 25 | </div> 26 | </section> 27 | </div> 28 | 29 | 30 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/layout/shell.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.layout') 6 | .controller('Shell', Shell); 7 | 8 | Shell.$inject = ['$timeout', 'config', 'logger', 'authService']; 9 | 10 | function Shell($timeout, config, logger, authService) { 11 | /*jshint validthis: true */ 12 | var vm = this; 13 | 14 | vm.title = config.appTitle; 15 | vm.busyMessage = 'Please wait ...'; 16 | vm.isBusy = true; 17 | vm.showSplash = true; 18 | //vm.userName = authService.OidcTokenManager().profile.name; 19 | 20 | activate(); 21 | 22 | function activate() { 23 | logger.success(config.appTitle + ' loaded!', null); 24 | // Using a resolver on all routes or dataservice.ready in every controller 25 | // dataservice.ready().then(function(){ 26 | // hideSplash(); 27 | // }); 28 | vm.mgr = authService.OidcTokenManager(); 29 | if (vm.mgr.expired) { 30 | vm.mgr.redirectForToken(); 31 | } 32 | 33 | hideSplash(); 34 | } 35 | 36 | function hideSplash() { 37 | //Force a 1 second delay so we can see the splash. 38 | $timeout(function() { 39 | vm.showSplash = false; 40 | }, 1000); 41 | } 42 | } 43 | })(); 44 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/layout/sidebar.html: -------------------------------------------------------------------------------- 1 | <div data-cc-sidebar when-done-animating="vm.sidebarReady()" data-ng-controller="Sidebar as vm"> 2 | <div class="sidebar-filler"></div> 3 | <div class="sidebar-dropdown"><a href="#">Menu</a></div> 4 | <div class="sidebar-inner"> 5 | <div class="sidebar-widget"></div> 6 | <ul class="navi"> 7 | <li class="nlightblue fade-selection-animation" data-ng-class="vm.isCurrent(r)" 8 | data-ng-repeat="r in vm.navRoutes"> 9 | <a href="#{{r.originalPath}}" 10 | data-ng-bind-html="r.settings.content"></a> 11 | </li> 12 | </ul> 13 | </div> 14 | </div> 15 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/layout/sidebar.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.layout') 6 | .controller('Sidebar', Sidebar); 7 | 8 | Sidebar.$inject = ['$route', 'routehelper']; 9 | 10 | function Sidebar($route, routehelper) { 11 | /*jshint validthis: true */ 12 | var vm = this; 13 | var routes = routehelper.getRoutes(); 14 | vm.isCurrent = isCurrent; 15 | //vm.sidebarReady = function(){console.log('done animating menu')}; // example 16 | 17 | activate(); 18 | 19 | function activate() { getNavRoutes(); } 20 | 21 | function getNavRoutes() { 22 | vm.navRoutes = routes.filter(function(r) { 23 | return r.settings && r.settings.nav; 24 | }).sort(function(r1, r2) { 25 | return r1.settings.nav - r2.settings.nav; 26 | }); 27 | } 28 | 29 | function isCurrent(route) { 30 | if (!route.title || !$route.current || !$route.current.title) { 31 | return ''; 32 | } 33 | var menuName = route.title; 34 | return $route.current.title.substr(0, menuName.length) === menuName ? 'current' : ''; 35 | } 36 | } 37 | })(); 38 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/layout/topnav.html: -------------------------------------------------------------------------------- 1 | <nav class="navbar navbar-fixed-top navbar-inverse"> 2 | <div class="navbar-header"> 3 | <a href="/" class="navbar-brand"><span class="brand-title">{{vm.title}}</span></a> 4 | <a class="btn navbar-btn navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> 5 | <span class="icon-bar"></span> 6 | <span class="icon-bar"></span> 7 | <span class="icon-bar"></span> 8 | </a> 9 | </div> 10 | <div class="navbar-collapse collapse"> 11 | <div class="pull-right navbar-logo"> 12 | <ul class="nav navbar-nav pull-right"> 13 | <li> 14 | <a href="#" > 15 | {{vm.userName}} 16 | </a> 17 | </li> 18 | <li class="dropdown dropdown-big"> 19 | <a href="http://www.angularjs.org" target="_blank"> 20 | <img src="content/images/AngularJS-small.png" /> 21 | </a> 22 | </li> 23 | 24 | </ul> 25 | </div> 26 | </div> 27 | </nav> -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/widgets/ccSidebar.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.widgets') 6 | .directive('ccSidebar', ccSidebar); 7 | 8 | /* @ngInject */ 9 | function ccSidebar () { 10 | // Opens and closes the sidebar menu. 11 | // Usage: 12 | // <div data-cc-sidebar"> 13 | // <div data-cc-sidebar whenDoneAnimating="vm.sidebarReady()"> 14 | // Creates: 15 | // <div data-cc-sidebar class="sidebar"> 16 | var directive = { 17 | link: link, 18 | restrict: 'A', 19 | scope: { 20 | whenDoneAnimating: '&?' 21 | } 22 | }; 23 | return directive; 24 | 25 | function link(scope, element, attrs) { 26 | var $sidebarInner = element.find('.sidebar-inner'); 27 | var $dropdownElement = element.find('.sidebar-dropdown a'); 28 | element.addClass('sidebar'); 29 | $dropdownElement.click(dropdown); 30 | 31 | function dropdown(e) { 32 | var dropClass = 'dropy'; 33 | e.preventDefault(); 34 | if (!$dropdownElement.hasClass(dropClass)) { 35 | $sidebarInner.slideDown(350, scope.whenDoneAnimating); 36 | $dropdownElement.addClass(dropClass); 37 | } else if ($dropdownElement.hasClass(dropClass)) { 38 | $dropdownElement.removeClass(dropClass); 39 | $sidebarInner.slideUp(350, scope.whenDoneAnimating); 40 | } 41 | } 42 | } 43 | } 44 | })(); 45 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/widgets/ccSpinner.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.widgets') 6 | .directive('ccSpinner', ccSpinner); 7 | 8 | // ccSpinner.$inject = ['$window']; 9 | 10 | /* @ngInject */ 11 | function ccSpinner ($window) { 12 | // Description: 13 | // Creates a new Spinner and sets its options 14 | // Usage: 15 | // <div data-cc-spinner="vm.spinnerOptions"></div> 16 | var directive = { 17 | link: link, 18 | restrict: 'A' 19 | }; 20 | return directive; 21 | 22 | function link(scope, element, attrs) { 23 | scope.spinner = null; 24 | scope.$watch(attrs.ccSpinner, function(options) { 25 | if (scope.spinner) { 26 | scope.spinner.stop(); 27 | } 28 | scope.spinner = new $window.Spinner(options); 29 | scope.spinner.spin(element[0]); 30 | }, true); 31 | } 32 | } 33 | })(); 34 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/widgets/ccWidgetClose.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.widgets') 6 | .directive('ccWidgetClose', ccWidgetClose); 7 | 8 | /* @ngInject */ 9 | function ccWidgetClose () { 10 | // Usage: 11 | // <a data-cc-widget-close></a> 12 | // Creates: 13 | // <a data-cc-widget-close="" href="#" class="wclose"> 14 | // <i class="fa fa-remove"></i> 15 | // </a> 16 | var directive = { 17 | link: link, 18 | template: '<i class="fa fa-remove"></i>', 19 | restrict: 'A' 20 | }; 21 | return directive; 22 | 23 | function link(scope, element, attrs) { 24 | attrs.$set('href', '#'); 25 | attrs.$set('wclose'); 26 | element.click(closeEl); 27 | 28 | function closeEl(e) { 29 | e.preventDefault(); 30 | element.parent().parent().parent().hide(100); 31 | } 32 | } 33 | } 34 | })(); 35 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/widgets/ccWidgetHeader.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.widgets') 6 | .directive('ccWidgetHeader', ccWidgetHeader); 7 | 8 | /* @ngInject */ 9 | function ccWidgetHeader () { 10 | //Usage: 11 | //<div data-cc-widget-header title="vm.map.title"></div> 12 | // Creates: 13 | // <div data-cc-widget-header="" 14 | // title="Avengers Movie" 15 | // allow-collapse="true" </div> 16 | var directive = { 17 | // link: link, 18 | scope: { 19 | 'title': '@', 20 | 'subtitle': '@', 21 | 'rightText': '@', 22 | 'allowCollapse': '@' 23 | }, 24 | templateUrl: 'app/widgets/widgetheader.html', 25 | restrict: 'A' 26 | }; 27 | return directive; 28 | 29 | // function link(scope, element, attrs) { 30 | // attrs.$set('class', 'widget-head'); 31 | // } 32 | } 33 | })(); 34 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/widgets/ccWidgetMinimize.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.widgets') 6 | .directive('ccWidgetMinimize', ccWidgetMinimize); 7 | 8 | /* @ngInject */ 9 | function ccWidgetMinimize () { 10 | // Usage: 11 | // <a data-cc-widget-minimize></a> 12 | // Creates: 13 | // <a data-cc-widget-minimize="" href="#"><i class="fa fa-chevron-up"></i></a> 14 | var directive = { 15 | link: link, 16 | template: '<i class="fa fa-chevron-up"></i>', 17 | restrict: 'A' 18 | }; 19 | return directive; 20 | 21 | function link(scope, element, attrs) { 22 | //$('body').on('click', '.widget .wminimize', minimize); 23 | attrs.$set('href', '#'); 24 | attrs.$set('wminimize'); 25 | element.click(minimize); 26 | 27 | function minimize(e) { 28 | e.preventDefault(); 29 | var $wcontent = element.parent().parent().next('.widget-content'); 30 | var iElement = element.children('i'); 31 | if ($wcontent.is(':visible')) { 32 | iElement.removeClass('fa fa-chevron-up'); 33 | iElement.addClass('fa fa-chevron-down'); 34 | } else { 35 | iElement.removeClass('fa fa-chevron-down'); 36 | iElement.addClass('fa fa-chevron-up'); 37 | } 38 | $wcontent.toggle(500); 39 | } 40 | } 41 | } 42 | })(); 43 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/widgets/widgetheader.html: -------------------------------------------------------------------------------- 1 | <div class="widget-head"> 2 | <div class="page-title pull-left">{{title}}</div> 3 | <small class="page-title-subtle" data-ng-show="subtitle">({{subtitle}})</small> 4 | <div class="widget-icons pull-right" data-ng-if="allowCollapse"> 5 | <a data-cc-widget-minimize></a> 6 | </div> 7 | <small class="pull-right page-title-subtle" data-ng-show="rightText">{{rightText}}</small> 8 | <div class="clearfix"></div> 9 | </div> -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/app/widgets/widgets.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.widgets', []); 5 | })(); 6 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/callback.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | <head> 4 | <title> 5 | 6 | 7 | 8 | 9 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/content/images/AngularJS-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/ServiceStack/Punchcard.Angular1JWT/src/client/content/images/AngularJS-small.png -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/content/images/avengersicon-xs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/ServiceStack/Punchcard.Angular1JWT/src/client/content/images/avengersicon-xs.png -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/content/images/avengersicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/ServiceStack/Punchcard.Angular1JWT/src/client/content/images/avengersicon.png -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/content/images/busy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/ServiceStack/Punchcard.Angular1JWT/src/client/content/images/busy.gif -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/content/images/gg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/ServiceStack/Punchcard.Angular1JWT/src/client/content/images/gg.png -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/content/images/gruntjs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/ServiceStack/Punchcard.Angular1JWT/src/client/content/images/gruntjs.jpg -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
    27 |
    28 |
    29 |
    30 |
    31 | Angular Modular Demo 32 |
    33 |
    34 |
    35 |
    36 |
    37 |
    38 |
    39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "es3": false, 7 | "forin": true, 8 | "freeze": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": "nofunc", 12 | "newcap": true, 13 | "noarg": true, 14 | "noempty": true, 15 | "nonbsp": true, 16 | "nonew": true, 17 | "plusplus": false, 18 | "quotmark": "single", 19 | "undef": true, 20 | "unused": false, 21 | "strict": false, 22 | "maxparams": 10, 23 | "maxdepth": 5, 24 | "maxstatements": 40, 25 | "maxcomplexity": 8, 26 | "maxlen": 120, 27 | 28 | "asi": false, 29 | "boss": false, 30 | "debug": false, 31 | "eqnull": true, 32 | "esnext": false, 33 | "evil": false, 34 | "expr": true, 35 | "funcscope": false, 36 | "globalstrict": false, 37 | "iterator": false, 38 | "lastsemic": false, 39 | "laxbreak": false, 40 | "laxcomma": false, 41 | "loopfunc": true, 42 | "maxerr": false, 43 | "moz": false, 44 | "multistr": true, 45 | "notypeof": false, 46 | "proto": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "sub": true, 50 | "supernew": false, 51 | "validthis": false, 52 | "noyield": false, 53 | 54 | "browser": true, 55 | "node": true, 56 | 57 | "globals": { 58 | "angular": false, 59 | "describe": false, 60 | "it": false, 61 | "beforeEach": false, 62 | "afterEach": false, 63 | "expect": false, 64 | "inject": false, 65 | "mockData": false, 66 | "sinon": false, 67 | "specHelper": false, 68 | "$controller": false, 69 | "$httpBackend": false, 70 | "$location": false, 71 | "$q": false, 72 | "$rootScope": false, 73 | "$route": false, 74 | "$": false, 75 | "ngMidwayTester": false 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/lib/bindPolyfill.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Phantom.js does not support Function.prototype.bind (at least not before v.2.0 3 | * That's just crazy. Everybody supports bind. 4 | * Read about it here: https://groups.google.com/forum/#!msg/phantomjs/r0hPOmnCUpc/uxusqsl2LNoJ 5 | * This polyfill is copied directly from MDN 6 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility 7 | */ 8 | if (!Function.prototype.bind) { 9 | /*jshint freeze: false */ 10 | Function.prototype.bind = function (oThis) { 11 | if (typeof this !== 'function') { 12 | // closest thing possible to the ECMAScript 5 13 | // internal IsCallable function 14 | throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); 15 | } 16 | 17 | var aArgs = Array.prototype.slice.call(arguments, 1), 18 | fToBind = this, 19 | FuncNoOp = function () {}, 20 | fBound = function () { 21 | return fToBind.apply(this instanceof FuncNoOp && oThis ? this : oThis, 22 | aArgs.concat(Array.prototype.slice.call(arguments))); 23 | }; 24 | 25 | FuncNoOp.prototype = this.prototype; 26 | fBound.prototype = new FuncNoOp(); 27 | 28 | return fBound; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/lib/mockData.js: -------------------------------------------------------------------------------- 1 | /*jshint maxlen:120 */ 2 | /*jshint -W079 */ 3 | var mockData = (function() { 4 | return { 5 | getMockAvengers: getMockAvengers 6 | }; 7 | 8 | function getMockAvengers() { 9 | return [ 10 | { 11 | 'id': 1017109, 12 | 'name': 'Black Widow/Natasha Romanoff (MAA)', 13 | 'description': 'Natasha Romanoff, also known as Black Widow, is a world-renowned super' + 14 | ' spy and one of S.H.I.E.L.D.\'s top agents. Her hand-to-hand combat skills, intelligence,' + 15 | ' and unpredictability make her a deadly secret weapon. True to her mysterious nature,' + 16 | ' Black Widow comes and goes as she pleases, but always appears exactly when her particular' + 17 | ' skills are needed.', 18 | 'thumbnail': { 19 | 'path': 'http://i.annihil.us/u/prod/marvel/i/mg/a/03/523219743a99b', 20 | 'extension': 'jpg' 21 | } 22 | }, 23 | { 24 | 'id': 1017105, 25 | 'name': 'Captain America/Steve Rogers (MAA)', 26 | 'description': 'During World War II, Steve Rogers enlisted in the military and was injected' + 27 | ' with a super-serum that turned him into super-soldier Captain America! He\'s a' + 28 | ' skilled strategist and even more skilled with his shield, but it\'s his courage' + 29 | ' and good heart that makes Captain America both a leader and a true hero. ', 30 | 'thumbnail': { 31 | 'path': 'http://i.annihil.us/u/prod/marvel/i/mg/3/10/52321928eaa72', 32 | 'extension': 'jpg' 33 | } 34 | }, 35 | { 36 | 'id': 1017108, 37 | 'name': 'Hawkeye/Clint Barton (MAA)', 38 | 'description': 'Hawkeye is an expert archer with an attitude just as on-target as his aim.' + 39 | ' His stealth combat experience and his ability to hit any target with any projectile' + 40 | ' make him a valuable member of the Avengers. However, he refuses to let things get' + 41 | ' too serious, as he has as many jokes as he does arrows!', 42 | 'thumbnail': { 43 | 'path': 'http://i.annihil.us/u/prod/marvel/i/mg/4/03/5232198a81c17', 44 | 'extension': 'jpg' 45 | } 46 | }, 47 | { 48 | 'id': 1017104, 49 | 'name': 'Iron Man/Tony Stark (MAA)', 50 | 'description': 'Tony Stark is the genius inventor/billionaire/philanthropist owner of Stark' + 51 | ' Industries. With his super high-tech Iron Man suit, he is practically indestructible,' + 52 | ' able to fly, and has a large selection of weapons to choose from - but it\'s Tony\'s' + 53 | ' quick thinking and ability to adapt and improvise that make him an effective leader' + 54 | ' of the Avengers.', 55 | 'thumbnail': { 56 | 'path': 'http://i.annihil.us/u/prod/marvel/i/mg/2/d0/5232190d42df2', 57 | 'extension': 'jpg' 58 | } 59 | }, 60 | { 61 | 'id': 1017106, 62 | 'name': 'Thor (MAA)', 63 | 'description': 'Thor is the Asgardian Prince of Thunder, the son of Odin, and the realm\'s' + 64 | ' mightiest warrior. He loves the thrill of battle and is always eager to show off his' + 65 | ' power to the other Avengers, especially the Hulk. Thor\'s legendary Uru hammer,' + 66 | ' Mjolnir, gives him the power to control thunder and the ability to fly. He\'s found' + 67 | ' a new home on Earth and will defend it as his own... even if he doesn\'t understand' + 68 | ' its sayings and customs.', 69 | 'thumbnail': { 70 | 'path': 'http://i.annihil.us/u/prod/marvel/i/mg/2/03/52321948a51f2', 71 | 'extension': 'jpg' 72 | } 73 | } 74 | ]; 75 | } 76 | })(); 77 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/lib/specHelper.js: -------------------------------------------------------------------------------- 1 | /*jshint -W079 */ 2 | var specHelper = (function() { 3 | var service = { 4 | fakeLogger: fakeLogger, 5 | fakeRouteProvider: fakeRouteProvider, 6 | injector: injector, 7 | verifyNoOutstandingHttpRequests: verifyNoOutstandingHttpRequests 8 | }; 9 | return service; 10 | 11 | function fakeLogger($provide) { 12 | $provide.value('logger', sinon.stub({ 13 | info: function() {}, 14 | error: function() {}, 15 | warning: function() {}, 16 | success: function() {} 17 | })); 18 | } 19 | 20 | function fakeRouteProvider($provide) { 21 | /** 22 | * Stub out the $routeProvider so we avoid 23 | * all routing calls, including the default route 24 | * which runs on every test otherwise. 25 | * Make sure this goes before the inject in the spec. 26 | */ 27 | $provide.provider('$route', function() { 28 | /* jshint validthis:true */ 29 | this.when = sinon.stub(); 30 | this.otherwise = sinon.stub(); 31 | 32 | this.$get = function() { 33 | return { 34 | // current: {}, // fake before each test as needed 35 | // routes: {} // fake before each test as needed 36 | // more? You'll know when it fails :-) 37 | }; 38 | }; 39 | }); 40 | } 41 | 42 | /** 43 | * Inspired by Angular; that's how they get the parms for injection 44 | */ 45 | function getFnParams (fn) { 46 | var fnText; 47 | var argDecl; 48 | 49 | var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; 50 | var FN_ARG_SPLIT = /,/; 51 | var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; 52 | var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; 53 | var params = []; 54 | if (fn.length) { 55 | fnText = fn.toString().replace(STRIP_COMMENTS, ''); 56 | argDecl = fnText.match(FN_ARGS); 57 | angular.forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) { 58 | arg.replace(FN_ARG, function(all, underscore, name) { 59 | params.push(name); 60 | }); 61 | }); 62 | } 63 | return params; 64 | } 65 | 66 | function injector () { 67 | var annotation, 68 | body = '', 69 | cleanupBody = '', 70 | mustAnnotate = false, 71 | params; 72 | 73 | if (typeof arguments[0] === 'function') { 74 | params = getFnParams(arguments[0]); 75 | } 76 | // else from here on assume that arguments are all strings 77 | else if (angular.isArray(arguments[0])) { 78 | params = arguments[0]; 79 | } 80 | else { 81 | params = Array.prototype.slice.call(arguments); 82 | } 83 | 84 | annotation = params.join('\',\''); // might need to annotate 85 | 86 | angular.forEach(params, function(name, ix) { 87 | var _name, 88 | pathName = name.split('.'), 89 | pathLen = pathName.length; 90 | 91 | if (pathLen > 1) { 92 | // name is a path like 'block.foo'. Can't use as identifier 93 | // assume last segment should be identifier name, e.g. 'foo' 94 | name = pathName[pathLen - 1]; 95 | mustAnnotate = true; 96 | } 97 | 98 | _name = '_' + name + '_'; 99 | params[ix] = _name; 100 | body += name + '=' + _name + ';'; 101 | cleanupBody += 'delete window.' + name + ';'; 102 | 103 | // todo: tolerate component names that are invalid JS identifiers, e.g. 'burning man' 104 | }); 105 | 106 | var fn = 'function(' + params.join(',') + '){' + body + '}'; 107 | 108 | if (mustAnnotate) { 109 | fn = '[\'' + annotation + '\',' + fn + ']'; 110 | } 111 | 112 | var exp = 'inject(' + fn + ');' + 113 | 'afterEach(function(){' + cleanupBody + '});'; // remove from window. 114 | 115 | //Function(exp)(); // the assigned vars will be global. `afterEach` will remove them 116 | /* jshint evil:true */ 117 | new Function(exp)(); 118 | 119 | // Alternative that would not touch window but would require eval()!! 120 | // Don't do `Function(exp)()` and don't do afterEach cleanup 121 | // Instead do .. 122 | // return exp; 123 | // 124 | // Then caller must say something like: 125 | // eval(specHelper.injector('$log', 'foo')); 126 | } 127 | 128 | function verifyNoOutstandingHttpRequests () { 129 | afterEach(inject(function($httpBackend) { 130 | $httpBackend.verifyNoOutstandingExpectation(); 131 | $httpBackend.verifyNoOutstandingRequest(); 132 | })); 133 | } 134 | })(); 135 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/midway/controller.spec.js: -------------------------------------------------------------------------------- 1 | //http://www.yearofmoo.com/2013/01/full-spectrum-testing-with-angularjs-and-karma.html 2 | //https://github.com/yearofmoo-articles/AngularJS-Testing-Article 3 | describe('Midway: controllers and routes', function() { 4 | var tester; 5 | beforeEach(function() { 6 | if (tester) { 7 | tester.destroy(); 8 | } 9 | tester = ngMidwayTester('app'); 10 | }); 11 | 12 | beforeEach(function () { 13 | module('app', specHelper.fakeLogger); 14 | }); 15 | 16 | it('should load the Avengers controller properly when /avengers route is accessed', function(done) { 17 | tester.visit('/avengers', function() { 18 | expect(tester.path()).to.equal('/avengers'); 19 | var current = tester.inject('$route').current; 20 | var controller = current.controller; 21 | var scope = current.scope; 22 | expect(controller).to.equal('Avengers'); 23 | done(); 24 | }); 25 | }); 26 | 27 | it('should load the Dashboard controller properly when / route is accessed', function(done) { 28 | tester.visit('/', function() { 29 | expect(tester.path()).to.equal('/'); 30 | var current = tester.inject('$route').current; 31 | var controller = current.controller; 32 | var scope = current.scope; 33 | expect(controller).to.equal('Dashboard'); 34 | done(); 35 | }); 36 | }); 37 | 38 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/midway/dataservice.spec.js: -------------------------------------------------------------------------------- 1 | describe('Midway: dataservice requests', function() { 2 | var dataservice; 3 | var tester; 4 | 5 | beforeEach(function() { 6 | if (tester) { 7 | tester.destroy(); 8 | } 9 | tester = ngMidwayTester('app'); 10 | }); 11 | 12 | beforeEach(function() { 13 | dataservice = tester.inject('dataservice'); 14 | expect(dataservice).not.to.equal(null); 15 | }); 16 | 17 | describe('getAvengers function', function () { 18 | it('should return 7 Avengers', function (done) { 19 | dataservice.getAvengers().then(function(data) { 20 | expect(data).not.to.equal(null); 21 | expect(data.length).to.equal(7); 22 | done(); 23 | }); 24 | // $rootScope.$apply(); 25 | }); 26 | 27 | it('should contain Black Widow', function (done) { 28 | dataservice.getAvengers().then(function(data) { 29 | expect(data).not.to.equal(null); 30 | var hasBlackWidow = data.some(function isPrime(element, index, array) { 31 | return element.name.indexOf('Black Widow') >= 0; 32 | }); 33 | expect(hasBlackWidow).to.be.true; 34 | done(); 35 | }); 36 | // $rootScope.$apply(); 37 | }); 38 | }); 39 | 40 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/midway/template.spec.js: -------------------------------------------------------------------------------- 1 | describe('Midway: templates', function() { 2 | it('should load the template for the avengers view properly', 3 | function(done) { 4 | var tester = ngMidwayTester('app'); 5 | tester.visit('/avengers', function() { 6 | var current = tester.inject('$route').current; 7 | var controller = current.controller; 8 | var template = current.templateUrl; 9 | expect(template).to.match(/avengers\/avengers\.html/); 10 | tester.destroy(); 11 | done(); 12 | }); 13 | }); 14 | 15 | it('should load the template for the dashboard view properly', 16 | function(done) { 17 | var tester = ngMidwayTester('app'); 18 | tester.visit('/', function() { 19 | var current = tester.inject('$route').current; 20 | var controller = current.controller; 21 | var template = current.templateUrl; 22 | expect(template).to.match(/dashboard\/dashboard\.html/); 23 | tester.destroy(); 24 | done(); 25 | }); 26 | }); 27 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/midway/view-requests.spec.js: -------------------------------------------------------------------------------- 1 | describe('Midway: view requests', function() { 2 | var tester; 3 | beforeEach(function() { 4 | if (tester) { 5 | tester.destroy(); 6 | } 7 | tester = ngMidwayTester('app'); 8 | }); 9 | 10 | beforeEach(function() { 11 | module('app', specHelper.fakeLogger); 12 | }); 13 | 14 | it('should goto the dashboard by default', function(done) { 15 | tester.visit('/', function() { 16 | expect(tester.viewElement().html()).to.contain('id="dashboard-view"'); 17 | done(); 18 | }); 19 | }); 20 | 21 | it('should have a working avengers request', function(done) { 22 | tester.visit('/avengers', function() { 23 | expect(tester.viewElement().html()).to.contain('title="Avengers"'); 24 | done(); 25 | }); 26 | }); 27 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/specs/avengers-route.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('avengers', function () { 3 | describe('route', function () { 4 | var controller; 5 | 6 | beforeEach(function() { 7 | module('app', specHelper.fakeLogger); 8 | specHelper.injector(function($httpBackend, $location, $rootScope, $route) {}); 9 | $httpBackend.expectGET('app/avengers/avengers.html').respond(200); 10 | }); 11 | 12 | it('should map /avengers route to avengers View template', function () { 13 | expect($route.routes['/avengers'].templateUrl). 14 | to.equal('app/avengers/avengers.html'); 15 | }); 16 | 17 | it('should route / to the avengers View', function () { 18 | $location.path('/avengers'); 19 | $rootScope.$apply(); 20 | expect($route.current.templateUrl).to.equal('app/avengers/avengers.html'); 21 | }); 22 | }); 23 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/specs/avengers.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('app.avengers', function() { 3 | var controller; 4 | 5 | beforeEach(function() { 6 | module('app', function($provide) { 7 | specHelper.fakeRouteProvider($provide); 8 | specHelper.fakeLogger($provide); 9 | }); 10 | specHelper.injector(function($controller, $q, $rootScope, dataservice) {}); 11 | }); 12 | 13 | beforeEach(function () { 14 | sinon.stub(dataservice, 'getAvengers', function() { 15 | var deferred = $q.defer(); 16 | deferred.resolve(mockData.getMockAvengers()); 17 | return deferred.promise; 18 | }); 19 | 20 | sinon.stub(dataservice, 'ready', function() { 21 | var deferred = $q.defer(); 22 | deferred.resolve({test: 123}); 23 | return deferred.promise; 24 | }); 25 | 26 | controller = $controller('Avengers'); 27 | $rootScope.$apply(); 28 | }); 29 | 30 | describe('Avengers controller', function() { 31 | it('should be created successfully', function () { 32 | expect(controller).to.be.defined; 33 | }); 34 | 35 | describe('after activate', function() { 36 | it('should have title of Avengers', function() { 37 | expect(controller.title).to.equal('Avengers'); 38 | }); 39 | 40 | it('should have 5 Avengers', function() { 41 | expect(controller.avengers).to.have.length(5); 42 | }); 43 | }); 44 | }); 45 | 46 | specHelper.verifyNoOutstandingHttpRequests(); 47 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/specs/dashboard-route.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('dashboard', function () { 3 | describe('route', function () { 4 | var controller; 5 | 6 | beforeEach(function() { 7 | module('app', specHelper.fakeLogger); 8 | specHelper.injector(function($httpBackend, $location, $rootScope, $route) {}); 9 | $httpBackend.expectGET('app/dashboard/dashboard.html').respond(200); 10 | }); 11 | 12 | it('should map / route to dashboard View template', function () { 13 | expect($route.routes['/'].templateUrl). 14 | to.equal('app/dashboard/dashboard.html'); 15 | }); 16 | 17 | it('should route / to the dashboard View', function () { 18 | $location.path('/'); 19 | $rootScope.$digest(); 20 | expect($route.current.templateUrl).to.equal('app/dashboard/dashboard.html'); 21 | }); 22 | 23 | it('should route /invalid to the otherwise (dashboard) route', function () { 24 | $location.path('/invalid'); 25 | $rootScope.$digest(); 26 | expect($route.current.templateUrl).to.equal('app/dashboard/dashboard.html'); 27 | }); 28 | }); 29 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/specs/dashboard.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('app.dashboard', function() { 3 | var controller; 4 | 5 | beforeEach(function() { 6 | module('app', function($provide) { 7 | specHelper.fakeRouteProvider($provide); 8 | specHelper.fakeLogger($provide); 9 | }); 10 | specHelper.injector(function($controller, $q, $rootScope, dataservice) {}); 11 | }); 12 | 13 | beforeEach(function () { 14 | sinon.stub(dataservice, 'getAvengerCount', function () { 15 | var deferred = $q.defer(); 16 | deferred.resolve(mockData.getMockAvengers().length); 17 | return deferred.promise; 18 | }); 19 | 20 | sinon.stub(dataservice, 'ready', function () { 21 | var deferred = $q.defer(); 22 | deferred.resolve({test: 123}); 23 | return deferred.promise; 24 | }); 25 | 26 | controller = $controller('Dashboard'); 27 | $rootScope.$apply(); 28 | }); 29 | 30 | describe('Dashboard controller', function() { 31 | it('should be created successfully', function () { 32 | expect(controller).to.be.defined; 33 | }); 34 | 35 | describe('after activate', function() { 36 | it('should have title of Dashboard', function () { 37 | expect(controller.title).to.equal('Dashboard'); 38 | }); 39 | 40 | it('should have news', function () { 41 | expect(controller.news).to.not.be.empty; 42 | }); 43 | 44 | it('should have at least 1 avenger', function () { 45 | expect(controller.avengers).to.have.length.above(0); 46 | }); 47 | 48 | it('should have Avenger Count of 5', function () { 49 | expect(controller.avengerCount).to.equal(5); 50 | }); 51 | }); 52 | }); 53 | 54 | specHelper.verifyNoOutstandingHttpRequests(); 55 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/specs/dataservice.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('dataservice', function () { 3 | var scope; 4 | var mocks = {}; 5 | 6 | beforeEach(function () { 7 | module('app', function($provide) { 8 | specHelper.fakeRouteProvider($provide); 9 | specHelper.fakeLogger($provide); 10 | }); 11 | specHelper.injector(function($httpBackend, $rootScope, dataservice) {}); 12 | 13 | mocks.maaData = [{ 14 | data: {results: mockData.getMockAvengers()} 15 | }]; 16 | // sinon.stub(dataservice, 'getAvengers', function () { 17 | // var deferred = $q.defer(); 18 | // deferred.resolve(mockData.getMockAvengers()); 19 | // return deferred.promise; 20 | // }); 21 | }); 22 | 23 | it('should be registered', function() { 24 | expect(dataservice).not.to.equal(null); 25 | }); 26 | 27 | describe('getAvengers function', function () { 28 | it('should exist', function () { 29 | expect(dataservice.getAvengers).not.to.equal(null); 30 | }); 31 | 32 | it('should return 5 Avengers', function (done) { 33 | $httpBackend.when('GET', '/api/maa').respond(200, mocks.maaData); 34 | dataservice.getAvengers().then(function(data) { 35 | expect(data.length).to.equal(5); 36 | done(); 37 | }); 38 | $rootScope.$apply(); 39 | $httpBackend.flush(); 40 | }); 41 | 42 | it('should contain Black Widow', function (done) { 43 | $httpBackend.when('GET', '/api/maa').respond(200, mocks.maaData); 44 | dataservice.getAvengers().then(function(data) { 45 | var hasBlackWidow = data.some(function isPrime(element, index, array) { 46 | return element.name.indexOf('Black Widow') >= 0; 47 | }); 48 | expect(hasBlackWidow).to.be.true; 49 | done(); 50 | }); 51 | $rootScope.$apply(); 52 | $httpBackend.flush(); 53 | }); 54 | }); 55 | 56 | describe('getAvengerCount function', function () { 57 | it('should exist', function () { 58 | expect(dataservice.getAvengerCount).not.to.equal(null); 59 | }); 60 | 61 | it('should return 11 Avengers', function (done) { 62 | dataservice.getAvengerCount().then(function(count) { 63 | expect(count).to.equal(11); 64 | done(); 65 | }); 66 | $rootScope.$apply(); 67 | }); 68 | }); 69 | 70 | describe('getAvengersCast function', function () { 71 | it('should exist', function () { 72 | expect(dataservice.getAvengersCast).not.to.equal(null); 73 | }); 74 | 75 | it('should return 11 Avengers', function (done) { 76 | dataservice.getAvengersCast().then(function(data) { 77 | expect(data.length).to.equal(11); 78 | done(); 79 | }); 80 | $rootScope.$apply(); 81 | }); 82 | 83 | it('should contain Natasha', function (done) { 84 | dataservice.getAvengersCast() 85 | .then(function(data) { 86 | var hasBlackWidow = data.some(function isPrime(element, index, array) { 87 | return element.character.indexOf('Natasha') >= 0; 88 | }); 89 | expect(hasBlackWidow).to.be.true; 90 | done(); 91 | }); 92 | $rootScope.$apply(); 93 | }); 94 | }); 95 | 96 | describe('ready function', function () { 97 | it('should exist', function () { 98 | expect(dataservice.ready).not.to.equal(null); 99 | }); 100 | 101 | it('should return a resolved promise', function (done) { 102 | dataservice.ready() 103 | .then(function(data) { 104 | expect(true).to.be.true; 105 | done(); 106 | }, function(data) { 107 | expect('promise rejected').to.be.true; 108 | done(); 109 | }); 110 | $rootScope.$apply(); 111 | }); 112 | }); 113 | 114 | specHelper.verifyNoOutstandingHttpRequests(); 115 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/specs/exception-handler.provider.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('blocks.exception', function() { 3 | var exceptionHandlerProvider; 4 | var mocks = { 5 | errorMessage: 'fake error', 6 | prefix: '[TEST]: ' 7 | }; 8 | 9 | beforeEach(function() { 10 | module('blocks.exception', function($provide, _exceptionHandlerProvider_) { 11 | exceptionHandlerProvider = _exceptionHandlerProvider_; 12 | specHelper.fakeRouteProvider($provide); 13 | specHelper.fakeLogger($provide); 14 | }); 15 | specHelper.injector(function($rootScope) {}); 16 | }); 17 | 18 | describe('$exceptionHandler', function() { 19 | it('should have a dummy test', inject(function() { 20 | expect(true).to.equal(true); 21 | })); 22 | 23 | it('should be defined', inject(function($exceptionHandler) { 24 | expect($exceptionHandler).to.be.defined; 25 | })); 26 | 27 | it('should have configuration', inject(function($exceptionHandler) { 28 | expect($exceptionHandler.config).to.be.defined; 29 | })); 30 | 31 | describe('with appErrorPrefix', function() { 32 | beforeEach(function() { 33 | exceptionHandlerProvider.configure(mocks.prefix); 34 | }); 35 | 36 | it('should have exceptionHandlerProvider defined', inject(function() { 37 | expect(exceptionHandlerProvider).to.be.defined; 38 | })); 39 | 40 | it('should have exceptionHandlerProvider\'s appErrorPrefix defined', inject(function() { 41 | expect(exceptionHandlerProvider.$get().config.appErrorPrefix).to.be.defined; 42 | })); 43 | 44 | it('should have exceptionHandlerProvider\'s appErrorPrefix set properly', inject(function() { 45 | expect(exceptionHandlerProvider.$get().config.appErrorPrefix).to.equal(mocks.prefix); 46 | })); 47 | 48 | it('should throw an error when forced', inject(function() { 49 | expect(functionThatWillThrow).to.throw(); 50 | })); 51 | 52 | it('manual error is handled by decorator', function() { 53 | var exception; 54 | exceptionHandlerProvider.configure(mocks.prefix); 55 | try { 56 | $rootScope.$apply(functionThatWillThrow); 57 | } 58 | catch (ex) { 59 | exception = ex; 60 | expect(ex.message).to.equal(mocks.prefix + mocks.errorMessage); 61 | } 62 | }); 63 | }); 64 | }); 65 | 66 | function functionThatWillThrow() { 67 | throw new Error(mocks.errorMessage); 68 | } 69 | 70 | 71 | specHelper.verifyNoOutstandingHttpRequests(); 72 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/client/test/specs/sidebar.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('layout', function () { 3 | describe('sidebar', function () { 4 | var controller; 5 | 6 | beforeEach(function() { 7 | module('app', specHelper.fakeLogger); 8 | specHelper.injector(function($controller, $httpBackend, $location, $rootScope, $route) {}); 9 | }); 10 | 11 | beforeEach(function () { 12 | controller = $controller('Sidebar'); 13 | }); 14 | 15 | it('should have isCurrent() for / to return `current`', function () { 16 | $httpBackend.when('GET', 'app/dashboard/dashboard.html').respond(200); 17 | $location.path('/'); 18 | $httpBackend.flush(); 19 | $rootScope.$apply(); 20 | expect(controller.isCurrent($route.current)).to.equal('current'); 21 | }); 22 | 23 | it('should have isCurrent() for /avengers to return `current`', function () { 24 | $httpBackend.when('GET', 'app/avengers/avengers.html').respond(200); 25 | $location.path('/avengers'); 26 | $httpBackend.flush(); 27 | $rootScope.$apply(); 28 | expect(controller.isCurrent($route.current)).to.equal('current'); 29 | }); 30 | 31 | it('should have isCurrent() for non route not return `current`', function () { 32 | $httpBackend.when('GET', 'app/dashboard/dashboard.html').respond(200); 33 | $location.path('/invalid'); 34 | $httpBackend.flush(); 35 | $rootScope.$apply(); 36 | expect(controller.isCurrent({title: 'invalid'})).not.to.equal('current'); 37 | }); 38 | 39 | specHelper.verifyNoOutstandingHttpRequests(); 40 | }); 41 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/server/app.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | 'use strict'; 3 | 4 | var express = require('express'); 5 | var app = express(); 6 | var bodyParser = require('body-parser'); 7 | var compress = require('compression'); 8 | var cors = require('cors'); 9 | var errorHandler = require('./routes/utils/errorHandler')(); 10 | var favicon = require('serve-favicon'); 11 | var logger = require('morgan'); 12 | var port = process.env.PORT || 7200; 13 | var routes; 14 | 15 | var environment = process.env.NODE_ENV; 16 | 17 | app.use(bodyParser.urlencoded({extended: true})); 18 | app.use(bodyParser.json()); 19 | app.use(compress()); // Compress response data with gzip 20 | app.use(logger('dev')); 21 | app.use(favicon(__dirname + '/favicon.ico')); 22 | app.use(cors()); // enable ALL CORS requests 23 | app.use(errorHandler.init); 24 | 25 | routes = require('./routes/index')(app); 26 | 27 | console.log('About to crank up node'); 28 | console.log('PORT=' + port); 29 | console.log('NODE_ENV=' + environment); 30 | 31 | var source = ''; 32 | 33 | app.get('/ping', function(req, res, next) { 34 | console.log(req.body); 35 | res.send('pong'); 36 | }); 37 | 38 | switch (environment){ 39 | case 'production': 40 | console.log('** PRODUCTION ON AZURE **'); 41 | console.log('serving from ' + './build/'); 42 | process.chdir('./../../'); 43 | app.use('/', express.static('./build/')); 44 | break; 45 | case 'stage': 46 | case 'build': 47 | console.log('** BUILD **'); 48 | console.log('serving from ' + './build/'); 49 | app.use('/', express.static('./build/')); 50 | break; 51 | default: 52 | console.log('** DEV **'); 53 | console.log('serving from ' + './src/client/ and ./'); 54 | app.use('/', express.static('./src/client/')); 55 | app.use('/', express.static('./')); 56 | break; 57 | } 58 | 59 | app.listen(port, function() { 60 | console.log('Express server listening on port ' + port); 61 | console.log('env = ' + app.get('env') + 62 | '\n__dirname = ' + __dirname + 63 | '\nprocess.cwd = ' + process.cwd()); 64 | }); -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/server/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Estyn/ServiceStackJWT/e761db57b60ee1f25559f91e6878e6aa0a2161c8/ServiceStack/Punchcard.Angular1JWT/src/server/favicon.ico -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/server/routes/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app) { 2 | var jsonfileservice = require('./utils/jsonfileservice')(); 3 | 4 | app.get('/api/maa', getMaa); 5 | 6 | function getMaa(req, res, next) { 7 | var json = jsonfileservice.getJsonFromFile('/../../data/maa.json'); 8 | json[0].data.results.forEach(function(character) { 9 | var pos = character.name.indexOf('(MAA)'); 10 | character.name = character.name.substr(0, pos - 1); 11 | }); 12 | res.send(json); 13 | } 14 | }; -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/server/routes/utils/errorHandler.js: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | var service = { 3 | init: init, 4 | logErrors: logErrors 5 | }; 6 | return service; 7 | 8 | function init(err, req, res, next) { 9 | var status = err.statusCode || 500; 10 | if (err.message) { 11 | res.send(status, err.message); 12 | } else { 13 | res.send(status, err); 14 | } 15 | next(); 16 | } 17 | 18 | /* Our fall through error logger and errorHandler */ 19 | function logErrors(err, req, res, next) { 20 | var status = err.statusCode || 500; 21 | console.error(status + ' ' + (err.message ? err.message : err)); 22 | if (err.stack) { 23 | console.error(err.stack); 24 | } 25 | next(err); 26 | } 27 | }; -------------------------------------------------------------------------------- /ServiceStack/Punchcard.Angular1JWT/src/server/routes/utils/jsonfileservice.js: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | var service = { 3 | getJsonFromFile: getJsonFromFile 4 | }; 5 | return service; 6 | 7 | function getJsonFromFile(file) { 8 | var fs = require('fs'); 9 | var json = getConfig(file); 10 | return json; 11 | 12 | function readJsonFileSync(filepath, encoding) { 13 | if (typeof (encoding) === 'undefined') { 14 | encoding = 'utf8'; 15 | } 16 | var file = fs.readFileSync(filepath, encoding); 17 | return JSON.parse(file); 18 | } 19 | 20 | function getConfig(file) { 21 | var filepath = __dirname + file; 22 | return readJsonFileSync(filepath); 23 | } 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.ServiceStackJWT/JsonWebToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IdentityModel.Tokens; 4 | using System.Security.Claims; 5 | using System.Security.Cryptography.X509Certificates; 6 | 7 | namespace Punchcard.ServiceStackJWT 8 | { 9 | public static class JsonWebToken 10 | { 11 | private const string NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"; 12 | private const string RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"; 13 | private const string ActorClaimType = "http://schemas.xmlsoap.org/ws/2009/09/identity/claims/actor"; 14 | private const string StringClaimValueType = "http://www.w3.org/2001/XMLSchema#string"; 15 | 16 | public static ClaimsPrincipal ValidateToken(string token, X509Certificate2 certificate, string audience = null, string issuer = null) 17 | { 18 | 19 | var claims = ValidateIdentityTokenAsync(token, audience, certificate); 20 | 21 | return new ClaimsPrincipal(ClaimsIdentityFromJwt(claims, issuer)); 22 | } 23 | 24 | 25 | 26 | private static ClaimsIdentity ClaimsIdentityFromJwt(IEnumerable claims, string issuer) 27 | { 28 | var subject = new ClaimsIdentity("Federation", NameClaimType, RoleClaimType); 29 | //var claims = ClaimsFromJwt(jwtData, issuer); 30 | 31 | foreach (Claim claim in claims) 32 | { 33 | var type = claim.Type; 34 | if (type == ActorClaimType) 35 | { 36 | if (subject.Actor != null) 37 | { 38 | throw new InvalidOperationException(string.Format( 39 | "Jwt10401: Only a single 'Actor' is supported. Found second claim of type: '{0}', value: '{1}'", new object[] { "actor", claim.Value })); 40 | } 41 | 42 | subject.AddClaim(new Claim(type, claim.Value, claim.ValueType, issuer, issuer, subject)); 43 | 44 | continue; 45 | } 46 | if (type == "name") 47 | { 48 | subject.AddClaim(new Claim(NameClaimType, claim.Value, StringClaimValueType, issuer, issuer)); 49 | continue; 50 | } 51 | if (type == "role") 52 | { 53 | subject.AddClaim(new Claim(RoleClaimType, claim.Value, StringClaimValueType, issuer, issuer)); 54 | continue; 55 | } 56 | var newClaim = new Claim(type, claim.Value, claim.ValueType, issuer, issuer, subject); 57 | 58 | foreach (var prop in claim.Properties) 59 | { 60 | newClaim.Properties.Add(prop); 61 | } 62 | 63 | subject.AddClaim(newClaim); 64 | } 65 | 66 | return subject; 67 | } 68 | 69 | private static IEnumerable ValidateIdentityTokenAsync(string token, string audience, X509Certificate2 certificate) 70 | { 71 | var parameters = new TokenValidationParameters 72 | { 73 | ValidAudience = audience, 74 | ValidIssuer = "http://localhost:22530", 75 | IssuerSigningToken = new X509SecurityToken(certificate) 76 | 77 | }; 78 | 79 | var handler = new JwtSecurityTokenHandler(); 80 | SecurityToken jwt; 81 | var id = handler.ValidateToken(token, parameters, out jwt); 82 | 83 | return id.Claims; 84 | } 85 | 86 | 87 | } 88 | } -------------------------------------------------------------------------------- /ServiceStack/Punchcard.ServiceStackJWT/JsonWebTokenAuthProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Security.Cryptography.X509Certificates; 6 | using System.Threading; 7 | using System.Web; 8 | using Microsoft.IdentityModel.Protocols; 9 | using ServiceStack; 10 | using ServiceStack.Auth; 11 | using ServiceStack.Web; 12 | 13 | namespace Punchcard.ServiceStackJWT 14 | { 15 | public class JsonWebTokenAuthProvider : AuthProvider, IAuthWithRequest 16 | { 17 | private static string Name = "JWT"; 18 | private static string Realm = "/auth/JWT"; 19 | private const string MissingAuthHeader = "Missing Authorization Header"; 20 | private const string InvalidAuthHeader = "Invalid Authorization Header"; 21 | 22 | 23 | private string Audience { get; } 24 | private string Issuer { get; } 25 | private X509Certificate2 Certificate { get; } 26 | 27 | /// 28 | /// Creates a new JsonWebToken Auth Provider 29 | /// 30 | /// aThe url to get the configuration informaion from.. (er "http://localhost:22530/" + ".well-known/openid-configuration") 31 | /// The client for openID (eg js_oidc) 32 | 33 | public JsonWebTokenAuthProvider(string discoveryEndpoint, string audience = null) 34 | { 35 | Provider = Name; 36 | AuthRealm = Realm; 37 | Audience = audience; 38 | 39 | var configurationManager = new ConfigurationManager(discoveryEndpoint); 40 | 41 | var config = configurationManager.GetConfigurationAsync().Result; 42 | 43 | Certificate = new X509Certificate2(Convert.FromBase64String(config.JsonWebKeySet.Keys.First().X5c.First())); 44 | Issuer = config.Issuer; 45 | } 46 | 47 | public override object Authenticate(IServiceBase authService, IAuthSession session, Authenticate request) 48 | { 49 | var header = request.oauth_token; 50 | 51 | // if no auth header, 401 52 | if (string.IsNullOrEmpty(header)) 53 | { 54 | throw HttpError.Unauthorized(MissingAuthHeader); 55 | } 56 | 57 | var headerData = header.Split(' '); 58 | 59 | // if header is missing bearer portion, 401 60 | if (string.Compare(headerData[0], "BEARER", StringComparison.OrdinalIgnoreCase) != 0) 61 | { 62 | throw HttpError.Unauthorized(InvalidAuthHeader); 63 | } 64 | 65 | try 66 | { 67 | 68 | // set current principal to the validated token principal 69 | Thread.CurrentPrincipal = JsonWebToken.ValidateToken(headerData[1], Certificate, Audience, Issuer); 70 | 71 | if (HttpContext.Current != null) 72 | { 73 | // set the current request's user the the decoded principal 74 | HttpContext.Current.User = Thread.CurrentPrincipal; 75 | } 76 | 77 | // set the session's username to the logged in user 78 | session.UserName = Thread.CurrentPrincipal.Identity.Name; 79 | 80 | return OnAuthenticated(authService, session, new AuthTokens(), new Dictionary()); 81 | } 82 | catch (Exception ex) 83 | { 84 | throw new HttpError(HttpStatusCode.Unauthorized, ex); 85 | } 86 | } 87 | 88 | 89 | /// 90 | /// 91 | /// 92 | /// 93 | public override bool IsAuthorized(IAuthSession session, IAuthTokens tokens, Authenticate request = null) 94 | { 95 | return HttpContext.Current.User.Identity.IsAuthenticated && session.IsAuthenticated && string.Equals(session.UserName, HttpContext.Current.User.Identity.Name, StringComparison.OrdinalIgnoreCase); 96 | } 97 | 98 | public void PreAuthenticate(IRequest request, IResponse response) 99 | { 100 | var header = request.Headers["Authorization"]; 101 | var authService = request.TryResolve(); 102 | authService.Request = request; 103 | 104 | // pass auth header in as oauth token to authentication 105 | authService.Post(new Authenticate 106 | { 107 | provider = Name, 108 | oauth_token = header 109 | }); 110 | } 111 | 112 | } 113 | } -------------------------------------------------------------------------------- /ServiceStack/Punchcard.ServiceStackJWT/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Punchcard.ServiceStackJWT")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Punchcard.ServiceStackJWT")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("65782666-7e93-40ea-bdd3-e74c06ef93fa")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.ServiceStackJWT/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ServiceStack/Punchcard.ServiceStackJWT/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | --------------------------------------------------------------------------------