How to Add auth_time claim in during jwt creation via help of SecurityTokenDescriptor and ClaimsIdentity - jwt

I am creating my jwt from following code. What i needed is auth_time claim which would be like something like
"nbf": 1582109929,
"exp": 1582110229,
"iat": 1582109929,
but I don't know how can I assign time value in above format or any way this claim automatically added with iat like value
public string GetIdTokenString(Dictionary<string, object> inputClaims, string secret)
{
string result = null;
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(secret);
List<Claim> claims = new List<Claim>();
foreach (var o in inputClaims)
{
string val = null;
if (o.Value != null)
{
Type t = o.Value.GetType();
bool isDict = t.IsGenericType /*&& t.GetGenericTypeDefinition() == typeof(Dictionary<,>)*/;
if (isDict)
{
val = JsonSerializer.Serialize(o.Value);
}
else
{
val = o.Value.ToString();
}
}
claims.Add(new Claim(o.Key, val));
}
claims.Add(new Claim("sub", Guid.NewGuid().ToString()));
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.Now.AddSeconds(60 * 5),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
Audience = ObjInitialRequest.JwtData.ContainsKey("client_id") ? ObjInitialRequest.JwtData["client_id"] : null,
Issuer = "...",//from well known configuration issuer
};
var token = tokenHandler.CreateToken(tokenDescriptor);
if (token != null && token is JwtSecurityToken)
{
result = (token as JwtSecurityToken).RawData;
}
}
catch (Exception ex)
{
//Logger
}
return result;
}

I were able to add it like following
new Claim("auth_time", ((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds).ToString(), ClaimValueTypes.Integer)

A short code
new Claim("auth_time", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(),ClaimValueTypes.Integer)

Related

Any way to create a JWT token with key size 512? and changing default minimum size requirement of AsymmetricSignatureProvider

I am currently getting following error:
IDX10630: The 'Microsoft.IdentityModel.Tokens.RsaSecurityKey, KeyId: '...', InternalId: '5a946596-9fe6-4c91-8c52-9b140849c7a4'.' for signing cannot be smaller than '2048' bits. KeySize: '512'
I use the following method:
public string GetIdTokenString(Dictionary<string, string> inputClaims, string privateKey)
{
string result = null;
try
{
var tokenHandler = new JwtSecurityTokenHandler();
privateKey = privateKey.Replace("-----BEGIN ENCRYPTED PRIVATE KEY-----", String.Empty).Replace("-----END ENCRYPTED PRIVATE KEY-----", String.Empty);
var privateKeyBytes = Convert.FromBase64String(privateKey);
byte[] privateKeyPasswordBytes = Encoding.UTF8.GetBytes(mypassword);
List<Claim> claims = new List<Claim>();
foreach (var o in inputClaims)
{
claims.Add(new Claim(o.Key, o.Value));
}
int length = 0;
RSA rSA = RSA.Create();
rSA.ImportEncryptedPkcs8PrivateKey(privateKeyPasswordBytes, privateKeyBytes, out length);
RsaSecurityKey securitykey = new RsaSecurityKey(rSA)
{
KeyId = "......"
};
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.UtcNow.AddSeconds(60 * 5),
Audience = ...,
Issuer = .....
};
tokenDescriptor.SigningCredentials = new SigningCredentials(securitykey, SecurityAlgorithms.RsaSha256Signature);
var token = tokenHandler.CreateToken(tokenDescriptor);
if (token != null && token is JwtSecurityToken)
{
result = (token as JwtSecurityToken).RawData;
}
}
catch (Exception ex)
{
Logger.Fatal(ex);
}
return result;
}
there is a code mentioned in post
Error Creating JWT Token using RSA Security Key with key size less than 2048
but I'm not able to run it in .net core 3.1
One more thing is about over riding value in
AsymmetricSignatureProvider.DefaultMinimumAsymmetricKeySizeInBitsForSigningMap
Any way i can change value of particular Key?
One thing i have tried which didn't work is
var mainclass = typeof(AsymmetricSignatureProvider)
.GetField(nameof(AsymmetricSignatureProvider.DefaultMinimumAsymmetricKeySizeInBitsForSigningMap), BindingFlags.Public | BindingFlags.Static );
var field = mainclass.GetValue(null) as Dictionary<string, int>;
if (field != null)
{
field["RS256"] = 512;
}
var mainclass2 = typeof(AsymmetricSignatureProvider).GetField(nameof(AsymmetricSignatureProvider.DefaultMinimumAsymmetricKeySizeInBitsForVerifyingMap), BindingFlags.Public | BindingFlags.Static);
var field2 = mainclass2.GetValue(null) as Dictionary<string, int>;
if (field2 != null)
{
field2["RS256"] = 512;
}
Following is the solution i have used
var mainclass = typeof(AsymmetricSignatureProvider)
.GetField(nameof(AsymmetricSignatureProvider.DefaultMinimumAsymmetricKeySizeInBitsForSigningMap), BindingFlags.Public | BindingFlags.Static);
var field = mainclass.GetValue(null) as Dictionary<string, int>;
if (field != null)
{
field["RS256"] = 512;
}
var mainclass2 = typeof(AsymmetricSignatureProvider).GetField(nameof(AsymmetricSignatureProvider.DefaultMinimumAsymmetricKeySizeInBitsForVerifyingMap), BindingFlags.Public | BindingFlags.Static);
var field2 = mainclass2.GetValue(null) as Dictionary<string, int>;
if (field2 != null)
{
field2["RS256"] = 512;
}

opcua session was closed by client

I have written the attached OpcUaConnector class for opc-ua connection related activities.
But it is not handling session. For example:
In opc ua configuration disabled the endpoint
In kepserver configuration did runtime > reinitializing
The windows service is throwing:
Source : system.Reactive.Core
InnerException : The session was closed by client
and stopping the windows service, as this error goes unhandled.
Can some one suggest how to handle session in opc-ua?
public class OpcUaConnector
{
private static SimplerAES simplerAES = new SimplerAES();
private DataContainer dataCointainer = null;
private UaTcpSessionChannel channel;
private string opcServerName = string.Empty;
private string opcUserId = string.Empty;
private string opcPassword = string.Empty;
private static ILog LogOpcStore;
private static System.IDisposable token;
private static uint id;
public OpcConnector(ILog Log)
{
IntializeLogOpcStore(Log);
}
private static void IntializeLogOpcStore(ILog Log)
{
LogOpcStore = Log;
}
public async Task OpenOpcConnection()
{
try
{
if ((!string.IsNullOrEmpty(this.opcServerName) & (this.opcServerName != AppMain.MyAppSettings.OpcServer)) ||
(!string.IsNullOrEmpty(this.opcUserId) & (this.opcUserId != AppMain.MyAppSettings.OpcUserId)) ||
(!string.IsNullOrEmpty(this.opcPassword) & (this.opcPassword != AppMain.MyAppSettings.OpcPassword)))
{
await channel.CloseAsync();
this.opcServerName = AppMain.MyAppSettings.OpcServer;
this.opcUserId = AppMain.MyAppSettings.OpcUserId;
this.opcPassword = AppMain.MyAppSettings.OpcPassword;
}
if (channel==null || (channel != null && (channel.State == CommunicationState.Closed || channel.State == CommunicationState.Faulted)))
{
var appDescription = new ApplicationDescription()
{
ApplicationName = "MyAppName",
ApplicationUri = $"urn:{System.Net.Dns.GetHostName()}:MyAppName",
ApplicationType = ApplicationType.Client,
};
//application data won't be deleted when uninstall
var certificateStore = new DirectoryStore(
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), MyAppName", "pki"),
true, true
);
//if the Ethernet cable unplugs or the Wifi drops out,
//you have some timeouts that can keep the session open for a while.
//There is a SessionTimeout (default of 2 min).
this.channel = new UaTcpSessionChannel(
appDescription,
certificateStore,
SignInOpc,
AppMain.MyAppSettings.OpcServer,
null,
options: new UaTcpSessionChannelOptions { SessionTimeout = 120000 });
await channel.OpenAsync();
//LogOpcStore.Info(String.Format("Opc connection sucessful"));
}
this.opcServerName = AppMain.MyAppSettings.OpcServer;
this.opcUserId = AppMain.MyAppSettings.OpcUserId;
this.opcPassword = AppMain.MyAppSettings.OpcPassword;
}
catch (Exception ex)
{
ServiceException serviceException = new ServiceException(ex.HResult + " " + ex.Message, "C052");
throw serviceException;
}
}
private static async Task RecursivelyFindNode(UaTcpSessionChannel channel, NodeId nodeid)
{
BrowseRequest browseRequest = new BrowseRequest
{
NodesToBrowse = new BrowseDescription[] { new BrowseDescription { NodeId = nodeid, BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All } },
};
BrowseResponse browseResponse = await channel.BrowseAsync(browseRequest);
foreach (var rd1 in browseResponse.Results[0].References ?? new ReferenceDescription[0])
{
uint chid = AppMain.MyTagDatabase.GetClientHandleByTag(rd1.DisplayName.ToString());
if (chid > 0)
{
AppMain.MyTagDatabase.UpdateNodeByClientHandle(chid, rd1.NodeId.ToString());
}
await RecursivelyFindNode(channel, ExpandedNodeId.ToNodeId(rd1.NodeId, channel.NamespaceUris));
}
}
public async Task CreateSubscription(DataContainer dc)
{
double curReadingValue;
try
{
dataCointainer = dc;
await RecursivelyFindNode(channel, NodeId.Parse(ObjectIds.RootFolder));
if (AppMain.MyTagDatabase.GetCntTagsNotInOpcServer() == AppMain.MyTagDatabase.GetTagCount())
{
//no need to create subscription
return;
}
//subscription timeout that is the product of PublishingInterval * LifetimeCount:
var subscriptionRequest = new CreateSubscriptionRequest
{
RequestedPublishingInterval = 1000f,
RequestedMaxKeepAliveCount = 30,
RequestedLifetimeCount = 30 * 3,
PublishingEnabled = true,
};
var subscriptionResponse = await channel.CreateSubscriptionAsync(subscriptionRequest);
id = subscriptionResponse.SubscriptionId;
var itemsToCreate = new MonitoredItemCreateRequest[AppMain.MyTagDatabase.GetTagHavingNodeCount()];
int i = 0;
foreach (var item in AppMain.MyTagDatabase.GetMyTagDatabase())
{
var itemKey = item.Key;
var itemValue = item.Value;
itemsToCreate[i] = new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse(itemValue.NodeId), AttributeId = AttributeIds.Value }, MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = itemKey, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } };
i++;
}
var itemsRequest = new CreateMonitoredItemsRequest
{
SubscriptionId = id,
ItemsToCreate = itemsToCreate,
};
var itemsResponse = await channel.CreateMonitoredItemsAsync(itemsRequest);
token = channel.Where(pr => pr.SubscriptionId == id).Subscribe(pr =>
{
// loop thru all the data change notifications
// receiving data change notifications here
var dcns = pr.NotificationMessage.NotificationData.OfType<DataChangeNotification>();
foreach (var dcn in dcns)
{
foreach (var min in dcn.MonitoredItems)
{
MyTag MyTag = new MyTag();
bool hasValue = AppMain.MyTagDatabase.GetMyTag(min.ClientHandle, out MyTag);
if (hasValue)
{
if (double.TryParse(min.Value.Value.ToString(), out curReadingValue))
{
//LogOpcStore.Info(String.Format("ClientHandle : {0} TagName : {1} SourceTimestamp : {2} ServerTimeStamp : {3} curReadingValue : {4}", min.ClientHandle, MyTag.TagName, min.Value.SourceTimestamp, min.Value.ServerTimestamp, curReadingValue));
AddDataPointToContainer(1, MyTag.TagName, min.Value.SourceTimestamp, curReadingValue);
}
}
}
}
});
}
catch (Exception ex)
{
//If the interruption lasts longer than these timeouts then the SessionChannel and Subscriptions will need to be recreated.
channel = null;
FatalServiceException fatalserviceException = new FatalServiceException(ex.Message, "C052");
throw fatalserviceException;
}
}
public async Task DeleteSubscription()
{
try
{
var request = new DeleteSubscriptionsRequest
{
SubscriptionIds = new uint[] { id }
};
await channel.DeleteSubscriptionsAsync(request);
token.Dispose();
}
catch (Exception ex)
{
ServiceException serviceException = new ServiceException(ex.Message, "C052");
throw serviceException;
}
}
private static async Task<IUserIdentity> SignInOpc(EndpointDescription endpoint)
{
IUserIdentity userIdentity = null;
if (endpoint.UserIdentityTokens.Any(p => p.TokenType == UserTokenType.Anonymous))
{
userIdentity = new AnonymousIdentity();
}
else if (endpoint.UserIdentityTokens.Any(p => p.TokenType == UserTokenType.UserName))
{
var userName = AppMain.MyAppSettings.OpcUserId;
var password = simplerAES.Decrypt(AppMain.MyAppSettings.OpcPassword);
userIdentity = new UserNameIdentity(userName, password);
}
return userIdentity;
}
private void AddDataPointToContainer(int dataType, string source, DateTime SourceTimestampUTC, double value)
{
ConditionValue conditionValue = new ConditionValue();
long timestamp = AppMain.ServerSyncTimeStore.ConvertDateTimeToTimeStampUTC(SourceTimestampUTC);
conditionValue.dataType = dataType;
conditionValue.source = source;
conditionValue.timestamp = timestamp;
conditionValue.SourceTimestampUTC = SourceTimestampUTC;
conditionValue.LocalTime = SourceTimestampUTC.ToLocalTime();
conditionValue.value = value;
//LogOpcStore.Info(String.Format("TagName : {0} SourceTimestampUTC : {1} timestamp : {2} LocalTime : {3} curReadingValue : {4}", source, SourceTimestampUTC, timestamp, SourceTimestampUTC.ToLocalTime(), value));
dataCointainer.AddDataPoint(conditionValue);
}
}
I see you are using the project https://github.com/convertersystems/opc-ua-client.
When a server closes the session and socket (as happens when you reinitialize Kepware) the client receives immediate notification that causes the client channel to fault. A faulted channel cannot be reopened, it should be aborted and a new channel should be created.
I made this standalone test, to show that you may have to catch an exception and recreate the channel and subscription. The point of this test is to subscribe to the CurrentTime node and collect 60 datachanges. The test should last a minute. If you re-init the Kepware server in the middle of the test, the code catches the exception and recreates the channel and subscription.
[TestMethod]
public async Task OpcConnectorTest()
{
var count = 0;
UaTcpSessionChannel channel = null;
while (count < 60)
{
try
{
channel = new UaTcpSessionChannel(
this.localDescription,
this.certificateStore,
new AnonymousIdentity(),
EndpointUrl,
SecurityPolicyUris.None,
loggerFactory: this.loggerFactory);
await channel.OpenAsync();
// create the keep alive subscription.
var subscriptionRequest = new CreateSubscriptionRequest
{
RequestedPublishingInterval = 1000f,
RequestedMaxKeepAliveCount = 30,
RequestedLifetimeCount = 30 * 3,
PublishingEnabled = true,
};
var subscriptionResponse = await channel.CreateSubscriptionAsync(subscriptionRequest).ConfigureAwait(false);
var id = subscriptionResponse.SubscriptionId;
var token = channel.Where(pr => pr.SubscriptionId == id).Subscribe(pr =>
{
// loop thru all the data change notifications
var dcns = pr.NotificationMessage.NotificationData.OfType<DataChangeNotification>();
foreach (var dcn in dcns)
{
foreach (var min in dcn.MonitoredItems)
{
Console.WriteLine($"sub: {pr.SubscriptionId}; handle: {min.ClientHandle}; value: {min.Value}");
count++;
}
}
});
var itemsRequest = new CreateMonitoredItemsRequest
{
SubscriptionId = id,
ItemsToCreate = new MonitoredItemCreateRequest[]
{
new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("i=2258"), AttributeId = AttributeIds.Value }, MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 12345, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }
},
};
var itemsResponse = await channel.CreateMonitoredItemsAsync(itemsRequest);
while (channel.State == CommunicationState.Opened && count < 60)
{
await Task.Delay(1000);
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.GetType()}. {ex.Message}");
}
}
if (channel != null)
{
Console.WriteLine($"Closing session '{channel.SessionId}'.");
await channel.CloseAsync();
}
}
I know this is an old post, but I stumbled upon this problem as well. For those interested:
The problem is related to the subscription(s).
When the following code is run:
token = channel.Where(pr => pr.SubscriptionId == id).Subscribe(pr =>
{
// loop thru all the data change notifications
// receiving data change notifications here
var dcns = pr.NotificationMessage.NotificationData.OfType<DataChangeNotification>();
foreach (var dcn in dcns)
{
foreach (var min in dcn.MonitoredItems)
{
MyTag MyTag = new MyTag();
bool hasValue = AppMain.MyTagDatabase.GetMyTag(min.ClientHandle, out MyTag);
if (hasValue)
{
if (double.TryParse(min.Value.Value.ToString(), out curReadingValue))
{
//LogOpcStore.Info(String.Format("ClientHandle : {0} TagName : {1} SourceTimestamp : {2} ServerTimeStamp : {3} curReadingValue : {4}", min.ClientHandle, MyTag.TagName, min.Value.SourceTimestamp, min.Value.ServerTimestamp, curReadingValue));
AddDataPointToContainer(1, MyTag.TagName, min.Value.SourceTimestamp, curReadingValue);
}
}
}
}
});
Observable.subscribe() takes multiple arguments. You should include what to do in case of an error. For example:
token = channel.Where(pr => pr.SubscriptionId == id).Subscribe(
pr => { code to run normally... },
ex => { Log.Info(ex.Message); },
() => { }
);
See http://reactivex.io/documentation/operators/subscribe.html for more information.

ConfirmEmailAsync() method is not working

I am having issue in confirming new user email. the Confirm email link works for first 20 minutes , but after 50 minutes the link expires. I have set the token expiration time to 24 hours. Please help me in resolving this issue. I am stuck on it for last 2 days:(.My code is as follows:
I am setting the token lifetime in Create() method in ApplicationUserManager as following:
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"))
{
TokenLifespan = _settings.ConfirmationAndResetTokenExpirationTimeSpan
};
}
And then In AccountsController, the Create method for new user is geiven below. The SendEmailAsync method consist of email subject, email body, generated password and the callback uri.
[Authorize(Roles = Roles.Bam.Name.Admin)]
[HttpPost]
[Route(Routes.Accounts.Template.Create, Name = Routes.Accounts.Name.Create)]
public async Task<IHttpActionResult> Create(CreateUserBindingModel createUserBindingModel)
{
IHttpActionResult result;
var memberNameExists = UserManager.Users.Any(x => x.MemberName.ToLower() == createUserBindingModel.MemberName.ToLower());
if (!memberNameExists)
{
var applicationUser = new ApplicationUser
{
UserName = createUserBindingModel.Email,
Email = createUserBindingModel.Email,
FirstName = createUserBindingModel.FirstName,
LastName = createUserBindingModel.LastName,
Company = createUserBindingModel.Company,
Location = createUserBindingModel.Location,
PhoneNumber = createUserBindingModel.PhoneNumber,
MemberName = createUserBindingModel.MemberName,
LastLoginDate = SqlDateTime.MinValue.Value,
CreateDate = DateTime.Now,
CreatedBy = User.Identity.GetUserId(),
UpdateDate = DateTime.Now,
UpdatedBy = User.Identity.GetUserId(),
TwoFactorEnabled = createUserBindingModel.TwoFactorEnabled,
SecurityResetRequired = true,
PasswordExpirationDate = DateTime.Now.AddDays(Convert.ToDouble(ConfigurationManager.AppSettings["PasswordExpirationDays"]))
};
if (!string.IsNullOrEmpty(createUserBindingModel.AvatarBase64))
{
var avatarBytes = Convert.FromBase64String(createUserBindingModel.AvatarBase64);
var resizedAvatarBytes = ImageResizer.ResizeImage(avatarBytes, _avatarWidth, _avatarHeight);
applicationUser.UserAvatar = new ApplicationUserAvatar
{
Avatar = resizedAvatarBytes
};
}
var generatedPassword = PasswordGenerator.GenerateStrongPassword(10, 10);
var identityResult = await UserManager.CreateAsync(applicationUser, generatedPassword);
if (identityResult.Succeeded)
{
await UserManager.AddToRolesAsync(applicationUser.Id, createUserBindingModel.Roles.ToArray());
var token = await UserManager.GenerateEmailConfirmationTokenAsync(applicationUser.Id);
var callbackUri = string.Format("{0}?userId={1}&token={2}", createUserBindingModel.EmailConfirmationCallbackUri, applicationUser.Id, HttpUtility.UrlEncode(token));
await UserManager.SendEmailAsync(applicationUser.Id, Email.Confirmation.Subject, string.Format(Email.Confirmation.Body, string.Format("{0} {1}", applicationUser.FirstName, applicationUser.LastName), callbackUri, generatedPassword, _settings.AccessTokenExpirationTimeSpan.TotalHours));
var userUrl = new Uri(Url.Link(Routes.Accounts.Name.Get, new { id = applicationUser.Id }));
var roles = await UserManager.GetRolesAsync(applicationUser.Id);
var contract = _accountsMapper.ToContract(applicationUser, roles);
result = Created(userUrl, contract);
}
else
{
result = GetErrorResult(identityResult);
}
}
else
{
ModelState.AddModelError(string.Empty, "Member Name already exists!");
result = BadRequest(ModelState);
}
return result;
}
Once the email is generated the UI has following JS angular code which gets executed and the provide the userid and token to service.
Angular JS code:
angular.module('confirmEmailModule').factory('confirmEmailFactory', function ($http) {
var factory = {};
factory.confirmEmail = function(userId, token) {
var encodedToken = encodeURIComponent(token);
var uri = '/identity/api/accounts/confirmemail?userId=' + userId + '&token=' + token;
return $http.post(uri);
}
return factory;
});
and the Service is :
[AllowAnonymous]
[HttpPost]
[Route(Routes.Accounts.Template.ConfirmEmail, Name = Routes.Accounts.Name.ConfirmEmail)]
public async Task<IHttpActionResult> ConfirmEmail([FromUri] string userId, [FromUri] string token)
{
//var decodedToken = HttpUtility.UrlDecode(token);
var identityResult = await UserManager.ConfirmEmailAsync(userId, token);
var result = identityResult.Succeeded ? StatusCode(HttpStatusCode.NoContent) : GetErrorResult(identityResult);
return result;
}
Please advice.
I found the solution to this issue. I am posting it if somebody faced the same issue. In my case the services and web API were on different servers. Different machine keys caused this issue. So I generated the machine key for my Web application and posted the same machine key in web.config file of Identity service. After that it worked. For more information on generating machine key, following link is helpful.
http://gunaatita.com/Blog/How-to-Generate-Machine-Key-using-IIS/1058
This is what worked for me. Hope it helps out;
public async Task<IActionResult> ConfirmEmail(string userId, string token)
{
if (userId == null || token == null)
{
return RedirectToAction("employees", "home");
}
var user = await userManager.FindByIdAsync(userId);
if (user == null)
{
ViewBag.ErrorMessage = $"The User ID {userId} is invalid";
return View("NotFound");
}
var result = await userManager.ConfirmEmailAsync(user, Uri.EscapeDataString(token));
if (result != null)
{
user.EmailConfirmed = true;
await userManager.UpdateAsync(user);
return View();
}
}

ASP MVC RouteConfig with authentication return error repository not found

I tried to make an authorization in my asp with my git client, so my git client will be requested an authorization from my server. When i tried to send a request to my git client, it was showing an error
repository http://localhost/git/user/try.git/info/ref not found
Here is my routeconfig
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
#region remoteURL
routes.MapRoute(
name: "RemoteURL",
url: "git/{project}.git/{*verb}",
defaults: new { controller = "Git", action = "Smart" }
);
routes.MapRoute(
name: "Git",
url: "git/{project}/{*verb}",
defaults: new { controller = "Git", action = "Smart" }
);
#endregion
#region Account;
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
#endregion;
}
and this is my controller that use an attribute :
public class GitController : Controller
{
[SmartGit]
public ActionResult Smart(string project, string service, string verb)
{
switch (verb)
{
case "info/refs":
return InfoRefs(project, service);
case "git-upload-pack":
return ExecutePack(project, "git-upload-pack");
case "git-receive-pack":
return ExecutePack(project, "git-receive-pack");
default:
return RedirectToAction("Tree", "Repository", new { Name = project });
}
}
and then this is my attribute smartgit
public class SmartGitAttribute : SmartAuthorizeAttribute
{
private const string AuthKey = "GitCodeGitAuthorize";
private GitCodeContext db = new GitCodeContext();
private string project;
private string verb;
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
var right = false;
var userfound = false;
List<string> paramParsing = new List<string>();
//url.Split("")
//base.OnAuthorization(filterContext);
var controller = filterContext.Controller as GitController;
if (controller == null)
return;
// git.exe not accept cookies as well as no session available
var auth = controller.HttpContext.Request.Headers["Authorization"];
if (!String.IsNullOrEmpty(auth))
{
var bytes = Convert.FromBase64String(auth.Substring(6));
var certificate = Encoding.ASCII.GetString(bytes);
var index = certificate.IndexOf(':');
var password = certificate.Substring(index + 1);
var username = certificate.Substring(0, index);
//var user = controller.MembershipService.Login(username, password);
if (WebSecurity.Login(username, password))
{
WebSecurity.Login(username, password);
userfound = true;
}
}
var projectField = controller.ValueProvider.GetValue("project");
var serviceField = controller.ValueProvider.GetValue("service");
var verbField = controller.ValueProvider.GetValue("service");
//filterContext.Controller.ValueProvider
var project = projectField == null ? null : projectField.AttemptedValue;
var service = serviceField == null ? null : serviceField.AttemptedValue;
var verb = verbField == null ? null : serviceField.AttemptedValue;
if (string.IsNullOrEmpty(service) && userfound) // redirect to git browser
{
right = true;
}
else if (string.Equals(service, "git-receive-pack", StringComparison.OrdinalIgnoreCase) && userfound) // git push
{
//right = controller.RepositoryService.CanWriteRepository(project, username);
right = true;
}
else if (string.Equals(service, "git-upload-pack", StringComparison.OrdinalIgnoreCase) && userfound ) // git fetch
{
//right = controller.RepositoryService.CanReadRepository(project, username);
right = true;
}
if (!userfound)
{
if (WebSecurity.CurrentUserName == "")
{
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.AddHeader("WWW-Authenticate", "Basic realm=\"coba\"");
filterContext.Result = new HttpUnauthorizedResult();
}
else
{
throw new UnauthorizedAccessException();
}
}
}
I found my own mistake, maybe my response doesn't have enough information so i decide to add a few information in my SmartGitAttribute
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusDescription = "Unauthorized";
filterContext.HttpContext.Response.AddHeader("WWW-Authenticate", "Basic realm=\"Secure Area\"");
filterContext.HttpContext.Response.Write("401, please authenticate");
filterContext.HttpContext.Response.StatusCode = 401;
filterContext.Result = new EmptyResult();
filterContext.HttpContext.Response.End();
this is reference that can help you to solve response authentication

How to decode SessionSecurityToken

Is it possible to decode a SessionSecurityToken?
I've set up a site to work with ThinkTecture IdentityServer using MachineKeySessionSecurityTokenHandler, and everything works as expected.
But now I need to pass the token to another service, but in an Authorization HTTP header instead of a cookie.
I've tried the following:
var cookie = HttpContext.Current.Request.Cookies[FederatedAuthentication.FederationConfiguration.CookieHandler.Name];
if (cookie != null)
{
var t = MachineKey.Unprotect(Convert.FromBase64String(cookie.Value), "System.IdentityModel.Services.MachineKeyTransform");
}
but this throws a System.Security.Cryptography.CryptographicException
Found the solution.
The only (easy) way of sending the data across the wire is to convert the SessionSecurityToken to a JwtSecurityToken and use the RawData property.
Sample implementation (dependent on ThinkTecture.IdentityModel):
public JwtSecurityToken ConvertSessionToJsonWebSecurityToken(SessionSecurityToken sessionToken)
{
var h = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers[typeof(JwtSecurityToken)] as JwtSecurityTokenHandler;
if (h != null)
{
var issuer = ((ValidatingIssuerNameRegistry)h.Configuration.IssuerNameRegistry).IssuingAuthorities.First().Name;
var audience = h.Configuration.AudienceRestriction.AllowedAudienceUris.First().AbsoluteUri;
var signingKey = ((ValidatingIssuerNameRegistry)h.Configuration.IssuerNameRegistry).IssuingAuthorities.First().SymmetricKeys.First();
var securityKey = ((NamedKeyIssuerTokenResolver)h.Configuration.IssuerTokenResolver).SecurityKeys.First().Value.First();
// Create token
var t = h.CreateToken(
null,
null,
(ClaimsIdentity)sessionToken.ClaimsPrincipal.Identity,
new Lifetime(sessionToken.ValidFrom, sessionToken.ValidTo),
new SigningCredentials(
securityKey,
Algorithms.HmacSha256Signature,
Algorithms.Sha256Digest));
// Serialize token for validaiton
var s = h.WriteToken(t);
// Validate token
var validationParameters = new TokenValidationParameters()
{
AllowedAudience = audience,
ValidIssuer = issuer,
SigningToken = new BinarySecretSecurityToken(Convert.FromBase64String(signingKey))
};
h.ValidateToken(s, validationParameters);
// Return token with correct type
return h.ReadToken(s) as JwtSecurityToken;
}
return null;
}
[Test]
public void GetToken_WhenValidSessionTokenExist_ShouldReturnValidJwtToken()
{
JwtSecurityToken c;
FederatedAuthentication.SessionAuthenticationModule.TryReadJwtTokenFromCookie(container.GetInstance<ISecurityTokenOperations>(), out c)
Assert.That(!string.IsNullOrEmpty(c.RawData));
}