I am trying to learn ASP.Net with Azure AD B2C Login / Register flow. I am running the demo here:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-web-api-dotnet?tabs=app-reg-ga
The C# code for the demo can be downloaded from https://github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi/archive/master.zip
I have gone all the way through the demo from the beginning and have completed all of the pre-requisites.
I am at the point now where I have signed in successfully and when I click the To-Do List link while debugging the application, I get a User Not Authorized (404) error.
I apologize in advance if I am not explaining what I think I am seeing very well, as I am very new to Azure and web programming. I am most comfortable with Windows Desktop applications interfacing with SQL Server, but I am trying to expand my knowledge, so please bear with me.
As I stated before, I can successfully log-in to the application, which I believe happens in the TaskWebApp project.
Here is the code where the error is happening, which is in the TasksController.cs in the TaskWebApp project:
namespace TaskWebApp.Controllers
{
[Authorize]
public class TasksController : Controller
{
private readonly string apiEndpoint = Globals.ServiceUrl + "/api/tasks/";
// GET: Makes a call to the API and retrieves the list of tasks
public async Task<ActionResult> Index()
{
try
{
// Retrieve the token with the specified scopes
var scope = new string[] { Globals.ReadTasksScope };
IConfidentialClientApplication cca = MsalAppBuilder.BuildConfidentialClientApplication();
var accounts = await cca.GetAccountsAsync();
AuthenticationResult result = await cca.AcquireTokenSilent(scope, accounts.FirstOrDefault()).ExecuteAsync();
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, apiEndpoint);
// Add token to the Authorization header and make the request
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = await client.SendAsync(request);
// Handle the response
switch (response.StatusCode)
{
case HttpStatusCode.OK:
string responseString = await response.Content.ReadAsStringAsync();
JArray tasks = JArray.Parse(responseString);
ViewBag.Tasks = tasks;
return View();
case HttpStatusCode.Unauthorized:
return ErrorAction("Please sign in again. " + response.ReasonPhrase);
default:
return ErrorAction("Error. Status code = " + response.StatusCode + ": " + response.ReasonPhrase);
}
}
catch (MsalUiRequiredException ex)
{
/*
If the tokens have expired or become invalid for any reason, ask the user to sign in again.
Another cause of this exception is when you restart the app using InMemory cache.
It will get wiped out while the user will be authenticated still because of their cookies, requiring the TokenCache to be initialized again
through the sign in flow.
*/
return new RedirectResult("/Account/SignUpSignIn?redirectUrl=/Tasks");
}
catch (Exception ex)
{
return ErrorAction("Error reading to do list: " + ex.Message);
}
}
The response status code in the Switch statement is 404.
When I debug, here is what I see:
var scope returns https://ShoppingCartB2C.onmicrosoft.com/tasks/demo.read
cca returns (I am questioning the format of the Authority property):
accounts returns nothing. A count of 0.
I believe 0 accounts is the problem.
When I try to get result, it goes to the catch block.
Here is the Web.config for the TaskWebApp project:
<configuration>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="ida:Tenant" value="ShoppingCartB2C.onmicrosoft.com" />
<!--MSAL cache needsĀ a tenantId along with the user's objectId to function. It retrieves these two from the claims returned in the id_token.
As tenantId is not guaranteed to be present in id_tokens issued by B2C unless the steps listed in this
document (https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/AAD-B2C-specifics#caching-with-b2c-in-msalnet).
If you are following the workarounds listed in the doc and tenantId claim (tid) is available in the user's token, then please change the
code in <ClaimsPrincipalsExtension.cs GetB2CMsalAccountId()> to let MSAL pick this from the claims instead -->
<add key="ida:TenantId" value="db1b052a-415c-4604-887c-e27b59860001" />
<add key="ida:ClientId" value="975f1457-e3e2-4cb8-b069-6b0b6b46611d" />
<add key="ida:ClientSecret" value="Gw4.3o-DRDr.j_828H-JMfsk_Jd1d-jQ5p" />
<add key="ida:AadInstance" value="https://ShoppingCartB2C.b2clogin.com/tfp/{0}/{1}" />
<add key="ida:RedirectUri" value="https://localhost:44316/" />
<add key="ida:SignUpSignInPolicyId" value="B2C_1_signupsignin1" />
<add key="ida:EditProfilePolicyId" value="b2c_1_profileediting1" />
<add key="ida:ResetPasswordPolicyId" value="b2c_1_passwordreset1" />
<add key="api:TaskServiceUrl" value="https://localhost:44332/" />
<!-- The following settings is used for requesting access tokens -->
<add key="api:ApiIdentifier" value="https://ShoppingCartB2C.onmicrosoft.com/tasks/" />
<add key="api:ReadScope" value="demo.read" />
<add key="api:WriteScope" value="demo.write" />
</appSettings>
And for the TaskService project:
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="ida:AadInstance" value="https://ShoppingCartB2C.b2clogin.com/{0}/{1}/v2.0/.well-known/openid-configuration" />
<add key="ida:Tenant" value="ShoppingCartB2C.onmicrosoft.com" />
<add key="ida:ClientId" value="975f1457-e3e2-4cb8-b069-6b0b6b46611d" />
<add key="ida:SignUpSignInPolicyId" value="B2C_1_signupsignin1" />
<!-- The following settings is used for requesting access tokens -->
<add key="api:ReadScope" value="demo.read" />
<add key="api:WriteScope" value="demo.write" />
</appSettings>
If you would like screen shots from Azure, or have questions about how that is configured, feel free to ask.
I am not concerned about exposing client secrets or AppId's because I am just following a demo. This is never going to be a production app.
I have not made any code modifications to the demo. Thanks for your help.
Edit: Showing API Permissions
Related
I'm working in a ASP.net full framework 4.7.2 web application. I'm trying to log to Application Insights. I added the default ApplicationInsights.config.
I wrote some code but I just can't seem to find out why it doesn't log to Application Insights.
Can anyone help mee or does anyone see my problemn? I checked the InstrumentationKey and that's set. When I Google on this issue, I just seem to end up at the new ILogger and .net core stuff that won't work for me.
I'm receiving all metrics just not my custom logging.
private static TraceTelemetry CreateTraceTelemetry(string message, SeverityLevel severityLevel, IDictionary<string, string> parameters = null)
{
// Create the telemetry
var traceTelemetry = new TraceTelemetry
{
Message = message,
SeverityLevel = severityLevel,
// We use local times in stead of UTC
Timestamp = DateTimeOffset.Now,
};
// Add all parameters
foreach (var keyValuePair in GetProperties(parameters))
{
traceTelemetry.Properties.Add(keyValuePair);
}
return traceTelemetry;
}
private void InternalLog(string message, SeverityLevel severityLevel, IDictionary<string, string> parameters)
{
// Create a new client each time
var telemetryClient = new TelemetryClient(TelemetryConfiguration.Active)
{
InstrumentationKey = InstrumentationKey,
};
// Add to the buffer queue
telemetryClient.TrackTrace(CreateTraceTelemetry(message: message, severityLevel: severityLevel, parameters: parameters));
// Send logging to Application Insights
telemetryClient.Flush();
}
ApplicationInsights.config
<?xml version="1.0" encoding="utf-8"?>
<ApplicationInsights xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
<InstrumentationKey>InstrumentationKeyOutOfApplicationInsights</InstrumentationKey>
<TelemetryInitializers>
<Add Type="Microsoft.ApplicationInsights.Web.AzureAppServiceRoleNameFromHostNameHeaderInitializer, Microsoft.AI.Web" />
<Add Type="Microsoft.ApplicationInsights.DependencyCollector.HttpDependenciesParsingTelemetryInitializer, Microsoft.AI.DependencyCollector" />
<Add Type="Microsoft.ApplicationInsights.WindowsServer.AzureRoleEnvironmentTelemetryInitializer, Microsoft.AI.WindowsServer" />
<Add Type="Microsoft.ApplicationInsights.WindowsServer.BuildInfoConfigComponentVersionTelemetryInitializer, Microsoft.AI.WindowsServer" />
<Add Type="Microsoft.ApplicationInsights.Web.WebTestTelemetryInitializer, Microsoft.AI.Web" />
<Add Type="Microsoft.ApplicationInsights.Web.SyntheticUserAgentTelemetryInitializer, Microsoft.AI.Web">
<!-- Extended list of bots:
search|spider|crawl|Bot|Monitor|BrowserMob|BingPreview|PagePeeker|WebThumb|URL2PNG|ZooShot|GomezA|Google SketchUp|Read Later|KTXN|KHTE|Keynote|Pingdom|AlwaysOn|zao|borg|oegp|silk|Xenu|zeal|NING|htdig|lycos|slurp|teoma|voila|yahoo|Sogou|CiBra|Nutch|Java|JNLP|Daumoa|Genieo|ichiro|larbin|pompos|Scrapy|snappy|speedy|vortex|favicon|indexer|Riddler|scooter|scraper|scrubby|WhatWeb|WinHTTP|voyager|archiver|Icarus6j|mogimogi|Netvibes|altavista|charlotte|findlinks|Retreiver|TLSProber|WordPress|wsr-agent|http client|Python-urllib|AppEngine-Google|semanticdiscovery|facebookexternalhit|web/snippet|Google-HTTP-Java-Client-->
<Filters>search|spider|crawl|Bot|Monitor|AlwaysOn</Filters>
</Add>
<Add Type="Microsoft.ApplicationInsights.Web.ClientIpHeaderTelemetryInitializer, Microsoft.AI.Web" />
<Add Type="Microsoft.ApplicationInsights.Web.OperationNameTelemetryInitializer, Microsoft.AI.Web" />
<Add Type="Microsoft.ApplicationInsights.Web.OperationCorrelationTelemetryInitializer, Microsoft.AI.Web" />
<Add Type="Microsoft.ApplicationInsights.Web.UserTelemetryInitializer, Microsoft.AI.Web" />
<Add Type="Microsoft.ApplicationInsights.Web.AuthenticatedUserIdTelemetryInitializer, Microsoft.AI.Web" />
<Add Type="Microsoft.ApplicationInsights.Web.AccountIdTelemetryInitializer, Microsoft.AI.Web" />
<Add Type="Microsoft.ApplicationInsights.Web.SessionTelemetryInitializer, Microsoft.AI.Web" />
</TelemetryInitializers>
<TelemetryModules>
<Add Type="Microsoft.ApplicationInsights.DependencyCollector.DependencyTrackingTelemetryModule, Microsoft.AI.DependencyCollector">
<ExcludeComponentCorrelationHttpHeadersOnDomains>
<!--
Requests to the following hostnames will not be modified by adding correlation headers.
Add entries here to exclude additional hostnames.
NOTE: this configuration will be lost upon NuGet upgrade.
-->
<Add>core.windows.net</Add>
<Add>core.chinacloudapi.cn</Add>
<Add>core.cloudapi.de</Add>
<Add>core.usgovcloudapi.net</Add>
</ExcludeComponentCorrelationHttpHeadersOnDomains>
<IncludeDiagnosticSourceActivities>
<Add>Microsoft.Azure.EventHubs</Add>
<Add>Microsoft.Azure.ServiceBus</Add>
</IncludeDiagnosticSourceActivities>
</Add>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.PerformanceCollectorModule, Microsoft.AI.PerfCounterCollector">
<!--
Use the following syntax here to collect additional performance counters:
<Counters>
<Add PerformanceCounter="\Process(??APP_WIN32_PROC??)\Handle Count" ReportAs="Process handle count" />
...
</Counters>
PerformanceCounter must be either \CategoryName(InstanceName)\CounterName or \CategoryName\CounterName
NOTE: performance counters configuration will be lost upon NuGet upgrade.
The following placeholders are supported as InstanceName:
??APP_WIN32_PROC?? - instance name of the application process for Win32 counters.
??APP_W3SVC_PROC?? - instance name of the application IIS worker process for IIS/ASP.NET counters.
??APP_CLR_PROC?? - instance name of the application CLR process for .NET counters.
-->
</Add>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse.QuickPulseTelemetryModule, Microsoft.AI.PerfCounterCollector" />
<Add Type="Microsoft.ApplicationInsights.WindowsServer.AppServicesHeartbeatTelemetryModule, Microsoft.AI.WindowsServer" />
<Add Type="Microsoft.ApplicationInsights.WindowsServer.AzureInstanceMetadataTelemetryModule, Microsoft.AI.WindowsServer">
<!--
Remove individual fields collected here by adding them to the ApplicationInsighs.HeartbeatProvider
with the following syntax:
<Add Type="Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.DiagnosticsTelemetryModule, Microsoft.ApplicationInsights">
<ExcludedHeartbeatProperties>
<Add>osType</Add>
<Add>location</Add>
<Add>name</Add>
<Add>offer</Add>
<Add>platformFaultDomain</Add>
<Add>platformUpdateDomain</Add>
<Add>publisher</Add>
<Add>sku</Add>
<Add>version</Add>
<Add>vmId</Add>
<Add>vmSize</Add>
<Add>subscriptionId</Add>
<Add>resourceGroupName</Add>
<Add>placementGroupId</Add>
<Add>tags</Add>
<Add>vmScaleSetName</Add>
</ExcludedHeartbeatProperties>
</Add>
NOTE: exclusions will be lost upon upgrade.
-->
</Add>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.DeveloperModeWithDebuggerAttachedTelemetryModule, Microsoft.AI.WindowsServer" />
<Add Type="Microsoft.ApplicationInsights.WindowsServer.UnhandledExceptionTelemetryModule, Microsoft.AI.WindowsServer" />
<Add Type="Microsoft.ApplicationInsights.WindowsServer.UnobservedExceptionTelemetryModule, Microsoft.AI.WindowsServer">
<!--</Add>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.FirstChanceExceptionStatisticsTelemetryModule, Microsoft.AI.WindowsServer">-->
</Add>
<Add Type="Microsoft.ApplicationInsights.Web.RequestTrackingTelemetryModule, Microsoft.AI.Web">
<Handlers>
<!--
Add entries here to filter out additional handlers:
NOTE: handler configuration will be lost upon NuGet upgrade.
-->
<Add>Microsoft.VisualStudio.Web.PageInspector.Runtime.Tracing.RequestDataHttpHandler</Add>
<Add>System.Web.StaticFileHandler</Add>
<Add>System.Web.Handlers.AssemblyResourceLoader</Add>
<Add>System.Web.Optimization.BundleHandler</Add>
<Add>System.Web.Script.Services.ScriptHandlerFactory</Add>
<Add>System.Web.Handlers.TraceHandler</Add>
<Add>System.Web.Services.Discovery.DiscoveryRequestHandler</Add>
<Add>System.Web.HttpDebugHandler</Add>
</Handlers>
</Add>
<Add Type="Microsoft.ApplicationInsights.Web.ExceptionTrackingTelemetryModule, Microsoft.AI.Web" />
<Add Type="Microsoft.ApplicationInsights.Web.AspNetDiagnosticTelemetryModule, Microsoft.AI.Web" />
</TelemetryModules>
<ApplicationIdProvider Type="Microsoft.ApplicationInsights.Extensibility.Implementation.ApplicationId.ApplicationInsightsApplicationIdProvider, Microsoft.ApplicationInsights" />
<TelemetrySinks>
<Add Name="default">
<TelemetryProcessors>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse.QuickPulseTelemetryProcessor, Microsoft.AI.PerfCounterCollector" />
<Add Type="Microsoft.ApplicationInsights.Extensibility.AutocollectedMetricsExtractor, Microsoft.ApplicationInsights" />
<Add Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.AdaptiveSamplingTelemetryProcessor, Microsoft.AI.ServerTelemetryChannel">
<MaxTelemetryItemsPerSecond>5</MaxTelemetryItemsPerSecond>
<ExcludedTypes>Event</ExcludedTypes>
</Add>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.AdaptiveSamplingTelemetryProcessor, Microsoft.AI.ServerTelemetryChannel">
<MaxTelemetryItemsPerSecond>5</MaxTelemetryItemsPerSecond>
<IncludedTypes>Event</IncludedTypes>
</Add>
</TelemetryProcessors>
<TelemetryChannel Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.ServerTelemetryChannel, Microsoft.AI.ServerTelemetryChannel" />
</Add>
</TelemetrySinks>
<!--
Learn more about Application Insights configuration with ApplicationInsights.config here:
http://go.microsoft.com/fwlink/?LinkID=513840
Note: If not present, please add <InstrumentationKey>Your Key</InstrumentationKey> to the top of this file.
-->
</ApplicationInsights>
After some hours of searching. Some other developer added the following line to disable the logging when running in debug.
if (System.Diagnostics.Debugger.IsAttached)
{
TelemetryConfiguration.Active.DisableTelemetry = true;
}
I am using the API SAML2.0 for ASP.net MVC and I used openssl to create the private and public key files and used a password for the private file. It generated two files ca.key and cas.pem, I used the ca.key file as the private key but I am getting this error
Additional information: The X.509 certificate could not be loaded from the file D:\Test Web Projects\TestSaml\TestSaml\Certificates\ca.key.
My users login to my mvc application the login process has nothing to do with SAML. I just check the users against my DB. The reason I am using SAML2.0 is because I need to direct my users for payment process to another external page which is my service provider. So once they click on a button on my page they should be redirected to the other website. The following is the sample code I built to verify if its working.
Web.config
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301880
-->
<configuration>
<appSettings>
<add key="TargetURL" value="https://btat2.paybill.com/consumer/SSO/SSOLogin?clientId=ReadyCapital"/>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
</configuration>
Saml.config
<?xml version="1.0"?>
<SAMLConfiguration xmlns="urn:componentspace:SAML:2.0:configuration">
<IdentityProvider Name="https://TestSaml"
Description="Test Identity Provider"
LocalCertificateFile="Certificates\ca.key"
LocalCertificatePassword="readycapital"/>
<PartnerServiceProviders>
<!-- MVC example -->
<PartnerServiceProvider Name="urn:oasis:names:tc:SAML:2.0:assertion"
Description="MVC Example Service Provider"
SignSAMLResponse="true"
SignAssertion="false"
EncryptAssertion="true"
AssertionConsumerServiceUrl="http://www.paybill.com/V2/Test/Login.aspx"
PartnerCertificateFile="Certificates\btat2.cert"/>
</PartnerServiceProviders>
</SAMLConfiguration>
Controller
public ActionResult Index(Profile profile)
{
string targetUrl = WebConfigurationManager.AppSettings["TargetURL"];
string userName = "00373219101";// WebConfigurationManager.AppSettings["SubjectName"];
SAMLAttribute[] attributes = new SAMLAttribute[2];
SAMLAttribute attribute = new SAMLAttribute("UserEmailAddress", SAMLIdentifiers.AttributeNameFormats.Unspecified, null, string.Empty);
attributes[0] = attribute;
SAMLAttribute attribute2 = new SAMLAttribute("MiscellaneousData", SAMLIdentifiers.AttributeNameFormats.Unspecified, null, string.Empty);
attributes[1] = attribute2;
SAMLIdentityProvider.InitiateSSO(Response, userName, attributes, targetUrl);
}
Did you check that the WebServer can actually access the files? Maybe use Microsoft Windows Sysinternals Process Monitor and check that the read operation is successful.
Replace the standalone .key file with a .pfx file both containing the certificate as well as the private key and link to that in IdentityProvider/#LocalCertificateFile
I'm having a problem with a Glimpse installation in a Sitecore 8.1 environment. I'm trying to create a simple Glimpse Security Policy which would check if the current user is a Sitecore admin.
if (!Sitecore.Context.User.IsAdministrator)
{
return RuntimePolicy.Off;
}
This is functionally the same as the example given in the sample code that Glimpse provides on installation through NuGet, which is,
var httpContext = policyContext.GetHttpContext();
if (!httpContext.User.IsInRole("Administrator"))
{
return RuntimePolicy.Off;
}
The problem is that when this code is hit, and the request is directed at glimpse.axd, the user is always reset to extranet\Anonymous. Sitecore always sets an anonymous user when there is none. Any requests that are not to the glimpse handler pass the check and set RuntimePolicy.On.
I have the following in the web.config
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/>
<add type="Sitecore.Web.RewriteModule, Sitecore.Kernel" name="SitecoreRewriteModule"/>
<add name="Glimpse" type="Glimpse.AspNet.HttpModule, Glimpse.AspNet" preCondition="integratedMode"/>
<add type="Sitecore.Nexus.Web.HttpModule,Sitecore.Nexus" name="SitecoreHttpModule"/>
<add type="Sitecore.Resources.Media.UploadWatcher, Sitecore.Kernel" name="SitecoreUploadWatcher"/>
<add type="Sitecore.IO.XslWatcher, Sitecore.Kernel" name="SitecoreXslWatcher"/>
<add type="Sitecore.IO.LayoutWatcher, Sitecore.Kernel" name="SitecoreLayoutWatcher"/>
<add type="Sitecore.Configuration.ConfigWatcher, Sitecore.Kernel" name="SitecoreConfigWatcher"/>
<remove name="Session"/>
<add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition=""/>
<add type="Sitecore.Analytics.RobotDetection.Media.MediaRequestSessionModule, Sitecore.Analytics.RobotDetection" name="MediaRequestSessionModule"/>
<add type="Sitecore.Web.HttpModule,Sitecore.Kernel" name="SitecoreHttpModuleExtensions"/>
<add name="SitecoreAntiCSRF" type="Sitecore.Security.AntiCsrf.SitecoreAntiCsrfModule, Sitecore.Security.AntiCsrf"/>
</modules>
The question is, why are the requests that are meant for /glimpse.axd not passing along the same authentication cookies as requests to the rest of the site?
I've created an ASP.NET MVC website. Then I've created a class library named Site.Scheduler where I wanted to put all my triggers and jobs.
I've created a simple job for testing purposes
public class CurrencyRatesJob : IJob
{
private readonly IBudgetsRepository budgetsRepository;
public CurrencyRatesJob(IBudgetsRepository budgetsRepository)
{
this.budgetsRepository = budgetsRepository;
}
public void Execute(IJobExecutionContext context)
{
try
{
var budgets = new BudgetsDTO();
var user = new UserDTO();
budgets.Sum = 1;
budgets.Name = "Quartz";
user.Email = "email#g.com";
budgetsRepository.InsertBudget(budgets, user);
}
catch (Exception ex)
{
throw new Quartz.JobExecutionException(ex);
}
}
}
and a Job Scheduler
public class CurrencyRatesJobScheduler
{
public static void GetCurrencyRates()
{
try
{
IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
IJobDetail job = JobBuilder.Create<CurrencyRatesJob>().Build();
ITrigger trigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule
(s =>
s.WithIntervalInSeconds(10)
.RepeatForever()
)
.Build();
scheduler.ScheduleJob(job, trigger);
}
catch (Exception ex)
{
ex.ToString();
}
}
}
To start the scheduler when application starts, I've added the following in Global.asax.cs
CurrencyRatesJobScheduler.GetCurrencyRates();
So after all that, I was expecting the job to execute every 10 seconds and insert all that info in the DB, but it doesn't do anything and I get no errors either.
Does anyone know what could be the issue?
EDIT:
So I've created all the necessary tables (executed the script from Quartz.NET) and I've added a new App.config file in my class library
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="quartz.scheduler.instanceName" value="MyQuartzScheduler" />
<add key="quartz.scheduler.instanceId" value="instance_one" />
<add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz" />
<add key="quartz.threadPool.threadCount" value="10" />
<add key="quartz.threadPool.threadPriority" value="1" />
<add key="quartz.jobStore.type" value="Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" />
<add key="quartz.jobStore.misfireThreshold" value="60000" />
<add key="quartz.jobStore.dataSource" value="default" />
<add key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz" />
<add key="quartz.jobStore.lockHandler.type" value="Quartz.Impl.AdoJobStore.UpdateLockRowSemaphore, Quartz" />
<add key="quartz.jobStore.tablePrefix" value="QRTZ_" />
<add key="quartz.dataSource.default.connectionString" value="Server=(local);Database=My.Database;UID=User;PWD=Password" />
<add key="quartz.dataSource.default.provider" value="SqlServer-20" />
<add key="quartz.jobStore.useProperties" value="true" />
</appSettings>
</configuration>
Still no luck. Besides that, no triggers or jobs were stored in the DB.
You need to call
scheduler.Start();
First thing that stands out, you haven't started scheduler. So quartz is not running.
IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
scheduler.Start();
After starting it the server will scan the db for job details/triggers and proceed accordingly.
However, you also want to add proper identities to your job detail/trigger. These are needed for quartz to create primary keys, otherwise you will get a SchedulerException.
IJobDetail job = JobBuilder.Create<CurrencyRatesJob>()
.WithIdentity("currencyJob", "group1")
.Build();
ITrigger trigger = TriggerBuilder.Create()
.StartNow()
.WithIdentity("currencyJob", "group1")
.WithSimpleSchedule(s => s.WithIntervalInSeconds(10).RepeatForever())
.Build();
Regarding your config file, you need to declare an appropriate quartz section and add the settings there (by default this is where StdSchedulerFactory looks to create properties)
<configuration>
<configSections>
<section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</configSections>
<quartz>
<add key="quartz.scheduler.instanceName" value="MyQuartzScheduler" />
<add key="quartz.scheduler.instanceId" value="AUTO" />
...
</quartz>
</configuration>
i am also facing the same issue. i fixed the issue by placing config information in the app.config in the consuming application. As Class Library does not capable of running independently. It should be referenced by another app maybe console or web site. we need to place all config items in the consuming application this may be help. cheers. happy sharing
I have a project which uses ADFS authentication in some cases. The configuration is read from a database and the URLs are different from customer to customer, so there are many configuration options which I can't hard-code in my Web.config.
The problem is that I get the following error:
ID1032: At least one 'audienceUri' must be specified in the SamlSecurityTokenRequirement when the AudienceUriMode is set to 'Always' or 'BearerKeyOnly'
But I don't get it always, and I can't reproduce it. This is pretty annoying since I can't really debug it as long as I can't reproduce it. And I'm not sure whether I did everything correct. Maybe some ADFS expert can have a look at it.
(Trusts between my relying parties and their corresponding ADFS servers have been established, of course.)
Here is my code (only interesting parts of it), please ask if anything is missing or unclear.
Some snippets from my Web.config:
<system.webServer>
<modules>
<add name="WSFederationAuthenticationModule" type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler" />
<add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler" />
<add name="ClaimsPrincipalHttpModule" type="Microsoft.IdentityModel.Web.ClaimsPrincipalHttpModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler" />
<!-- ... -->
</modules>
<!-- ... -->
</system.webServer>
<microsoft.identityModel>
<service>
<securityTokenHandlers>
<remove type="Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler" />
<add type="MyProject.MachineKeySessionSecurityTokenHandler" />
</securityTokenHandlers>
<federatedAuthentication>
<wsFederation passiveRedirectEnabled="false"
issuer="https://fail/IssuerEndpoint"
realm="https://fail/FederationResult"
homeRealm="https://fail"
requireHttps="true" />
</federatedAuthentication>
</service>
</microsoft.identityModel>
Those fail values will be overridden per request (see my Login() method below), but I have to specify something in my Web.config, so I chose to specify a valid URI at least. The default SessionSecurityTokenHandler had to be replaced because my service runs on multiple machines with DNS Round-Robin (sharing the same machine key).
Then I have a class I called AdfsTrustFilter which implements IAuthorizationFilter. I know it's bit of overhead, but due to the project structure, this filter is used as a global filter on every request (order is the least value in the whole project). In the OnAuthorization method, I complete the configuration as follows:
public sealed class AdfsTrustFilter : IAuthorizationFilter
public void OnAuthorization(AuthorizationContext filterContext)
// ...
var fam = FederatedAuthentication.WSFederationAuthenticationModule;
fam.ServiceConfiguration = new ServiceConfiguration
{
AudienceRestriction = new AudienceRestriction(AudienceUriMode.Always),
CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust,
// MyIssuerNameRegistry checks whether a fingerprint is known and some other stuff
IssuerNameRegistry = new MyIssuerNameRegistry()
};
// config.OwnPath contains something like "https://my.app.com/AppRoot/"
fam.ServiceConfiguration.AudienceRestriction.AllowedAudienceUris.Add(new Uri(config.OwnPath));
}
}
This is the code that starts the authentication:
public ActionResult Login()
{
// ...
// again something like "https://my.app.com/AppRoot/"
string baseUrl = Config.OwnPath.TrimEnd('/') + "/";
// adfs endpoint for this customer: i.e. "https://identity.provider.net/adfs/ls/"
string endpoint = Config.AdfsConfig.IdentityProvider.Endpoint;
// the code behind FederationResult is shown below
var signIn = new SignInRequestMessage(new Uri(endpoint), baseUrl + "/Adfs/FederationResult")
{
Context = baseUrl
};
var url = signIn.WriteQueryString();
return Redirect(url);
}
And finally the FederationResult callback:
public ActionResult FederationResult()
{
WSFederationAuthenticationModule fam = FederatedAuthentication.WSFederationAuthenticationModule;
HttpRequest request = System.Web.HttpContext.Current.Request;
if (fam.CanReadSignInResponse(request, true))
{
var id = (IClaimsIdentity) User.Identity;
// do something
}
// ...
}
P.S.: The ADFS server was recently upgraded from 2008 R2 to 2012, but this didn't change anything. ADFS version was always 2.0.
Since the exception says that you need the audienceUri, I would start by adding one under
<microsoft.IdentityModel>
<service>
<audienceUris>
<add value="https://yourdomain/theaudienceuri" />
The audienceUri is the Uri adfs returns to your application. You can override the engine to accept arbitrary return results which doesn't change the fact that indeed you need at least one uri in the config.