Skip to content

Commit

Permalink
feat(auth): add service accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
cyberhck committed Jun 3, 2021
1 parent f8435b1 commit 18de4c9
Show file tree
Hide file tree
Showing 8 changed files with 453 additions and 16 deletions.
24 changes: 24 additions & 0 deletions Micro.Auth.Business/Internal/Extensions/UserManager.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Micro.Auth.Storage;
using Microsoft.AspNetCore.Identity;
Expand All @@ -12,5 +14,27 @@ public static Task<User> GetUserByLogin(this UserManager<User> userManager, stri
? userManager.FindByEmailAsync(login)
: userManager.FindByNameAsync(login);
}

public static int GetTokenExpiry(this ClaimsPrincipal principal, int defaultValue = 15)
{
if (!principal.IsServiceAccount())
{
return defaultValue;
}

var expiry = principal.Claims.FirstOrDefault(x => x.Type == "token_expiry");
if (expiry == null)
{
return defaultValue; // by default if this claim doesn't exist on service account, we still return 15
}

var parsed = int.TryParse(expiry.Value, out var result);
return parsed ? result : defaultValue;
}

public static bool IsServiceAccount(this ClaimsPrincipal principal)
{
return principal.IsInRole("service_account");
}
}
}
6 changes: 4 additions & 2 deletions Micro.Auth.Business/Internal/Tokens/TokenFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
using System.Linq;
using System.Security.Claims;
using Micro.Auth.Business.Internal.Configs;
using Micro.Auth.Business.Internal.Extensions;
using Micro.Auth.Business.Internal.Keys;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using static System.Int32;

namespace Micro.Auth.Business.Internal.Tokens
{
Expand Down Expand Up @@ -35,8 +37,8 @@ public string GenerateJwtToken(ClaimsPrincipal principal)
{
Issuer = _identityConfig.Issuer,
Audience = _identityConfig.IssueForAudience,
Subject = new ClaimsIdentity(principal.Claims.Where(x => x.Type != securityStampClaimType)),
Expires = DateTime.UtcNow.AddMinutes(15),
Subject = new ClaimsIdentity(principal.Claims.Where(x => !new []{"token_expiry", securityStampClaimType}.Contains(x.Type))),
Expires = DateTime.UtcNow.AddMinutes(principal.GetTokenExpiry()),
SigningCredentials = new SigningCredentials(new RsaSecurityKey(_keyContainer.GetKey().PrivateKey) {KeyId = _keyContainer.GetKey().KeyId}, SecurityAlgorithms.RsaSha512)
};
var tokenHandler = new JwtSecurityTokenHandler();
Expand Down
8 changes: 6 additions & 2 deletions Micro.Auth.Business/Sessions/LoginSuccessResponse.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
namespace Micro.Auth.Business.Sessions
{
public class LoginSuccessResponse
public class LoginSuccessResponse : ServiceAccountLoginResponse
{
public string Jwt { set; get; }
public string RefreshToken { set; get; }
}

public class ServiceAccountLoginResponse
{
public string Jwt { set; get; }
}
}
24 changes: 13 additions & 11 deletions Micro.Auth.Business/Sessions/SessionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ namespace Micro.Auth.Business.Sessions
public interface ISessionService
{
Task<string> Refresh(string token);
Task<IEnumerable<RefreshToken>> GetForUser(string userId);
Task<(SignInResult, LoginSuccessResponse)> Login(LoginRequest loginRequest);
Task<(SignInResult, ServiceAccountLoginResponse)> Login(LoginRequest loginRequest);
}

public class SessionService : ISessionService
Expand Down Expand Up @@ -49,18 +48,14 @@ public async Task<string> Refresh(string token)
return _tokenFactory.GenerateJwtToken(principal);
}

public async Task<IEnumerable<RefreshToken>> GetForUser(string userId)
{
return await _refreshTokenRepository.FindByUser(userId);
}
public async Task<(SignInResult, LoginSuccessResponse)> Login(LoginRequest loginRequest)
public async Task<(SignInResult, ServiceAccountLoginResponse)> Login(LoginRequest loginRequest)
{
var user = await _userManager.GetUserByLogin(loginRequest.Login);
loginRequest.User = user;
return await AuthenticateUser(loginRequest);
}

private async Task<(SignInResult signInResult, LoginSuccessResponse login)> AuthenticateUser(LoginRequest login)
private async Task<(SignInResult signInResult, ServiceAccountLoginResponse login)> AuthenticateUser(LoginRequest login)
{
if (login.User == null)
{
Expand All @@ -73,10 +68,17 @@ public async Task<IEnumerable<RefreshToken>> GetForUser(string userId)
}
var principal = await _signInManager.CreateUserPrincipalAsync(login.User);
var jwt = _tokenFactory.GenerateJwtToken(principal);
var refreshToken = await _refreshTokenRepository.Create(login.ToRefreshToken(_uuidService.GenerateUuId("session")));
var res = new LoginSuccessResponse
if (!principal.IsServiceAccount())
{
var refreshToken = await _refreshTokenRepository.Create(login.ToRefreshToken(_uuidService.GenerateUuId("session")));
return (signInResult, new LoginSuccessResponse
{
Jwt = jwt,
RefreshToken = refreshToken.Value
});
}
var res = new ServiceAccountLoginResponse
{
RefreshToken = refreshToken.Value,
Jwt = jwt
};
return (signInResult, res);
Expand Down
25 changes: 24 additions & 1 deletion Micro.Auth.Storage/ApplicationContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using System.Collections.Generic;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Npgsql;
Expand Down Expand Up @@ -36,5 +38,26 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
options.MigrationsAssembly("Micro.Auth.Storage");
});
}

protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
var roles = new List<IdentityRole>
{
new IdentityRole("service_account") {Id = "9a6eb015-82d1-480c-b962-5aab596ef4f6", NormalizedName = "SERVICE_ACCOUNT"}
};
builder.Entity<IdentityRole>().HasData(roles);
var claims =
new List<IdentityRoleClaim<string>>{
new IdentityRoleClaim<string>()
{
Id = 1,
RoleId = roles[0].Id,
ClaimType = "token_expiry",
ClaimValue = "1440",
},
};
builder.Entity<IdentityRoleClaim<string>>().HasData(claims);
}
}
}
Loading

0 comments on commit 18de4c9

Please sign in to comment.