Is it possible to wire up external authentication after application startup? - identityserver4

As it is now, we add external authentication in ConfigureServices with somehting like
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect(...
During startup, I retrieve all federation configurations (both Oidc and WsFed) and wire them up in ConfigureServices.
But imagine a multi-tennant scenario where new federation configurations are added as new clients are added. The only solution I know of is to recycle the application so the ConfigureServices can run again, retrieve the entries for required integrations and add a call for each. This would really be useful to be able to do without the restart requirement. Any ideas are welcome.

You can have multiple AddOpenIdConnect in an application, the most important thing you need to do is to make sure these URLs are different for each one:
CallbackPath = new PathString("/signin-oidc");
SignedOutCallbackPath = new PathString("/signout-callback-oidc");
RemoteSignOutPath = new PathString("/signout-oidc");
However I don't know if you can dynamically add/remove handlers at runtime.

Yes you can add schema's dynamically, here is a sample https://github.com/aspnet/AuthSamples/tree/master/samples/DynamicSchemes
its old code but still accurate. Make sure to do postconfigure steps as well, its explained here. Here is another good answer about this.

Related

Securely storing third party API secrets in React & Shopify

Firstly, I am fairly new to both React and Shopify, so please bear that in mind with your answers.
I have created a basic Shopify app using their CLI tools which provide a React app. I now need to connect this app to a third party that manages custom shipping options. I therefore need to authenticate with this third party which then returns a token which I can use in my API calls. I've read many answers here about storing such tokens, some recommend localstorage/cookies, others state never do that but don't provide a clear answer to what one SHOULD do instead.
Currently I have something like the following:
let data = {
grant_type: 'client_credentials',
client_id: process.env.REACT_APP_THIRDPARTY_API_KEY,
client_secret: process.env.REACT_APP_THIRDPARTY_API_SECRET
}
axios.post('https://oauth.somethirdparty.se/v1/token', data).then(res => {
if (typeof window !== 'undefined') { // Check for browser
localStorage.setItem('t', res.data.token);
}
});
However I receive "undefined" errors for those env vars, and therefore the axios.post fails (works fine if I put in the key/secret directly here instead of the .env). Aside from this being unsecure according to the many posts here, I'm wondering if I can perhaps do something similar to what Shopify is doing, only my lack of knowledge prevents me from understanding exactly it is that they are doing!
The generated Shopify app uses the .env file in it's server.js file, like so:
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.October20,
IS_EMBEDDED_APP: true,
// This should be replaced with your preferred storage strategy
SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});
How can one safely store API credentials in my case? And please provide an actual example.
EDIT
I've found that if I modify the Shopify server.js file to console.log(process.env), I see all of the used env vars in the Terminal, and I guess the reason these are "undefined" when I try to log them in my app component is intentional so they are not exposed, which is great. Unfortunately it still doesn't help me when I need to connect to a third party service and get a token etc - how do I do that in this case?
This is a very easy question to answer. It is true, you always want to store your secrets in something like a dotenv file. Modern advanced frameworks like Rails even let you encrypt those, although eventually, you do need to ensure a secret key is present on your server for that.
So your public hosting service allows you to set environment variables. That is where you ensure they exist. You do not check those values into your public/private GitHub copy of your code.
So now, when your code executes, it has access to your secrets. It seems when you run your code, and you get undefined values, it is due to this, you have failed to set your environment properly. Read the documentation at your hosting service to figure that out.
Note that Shopify is not unique, 99% of all services operate this way. So you should have no trouble finding an answer to your problem.

How to pass deployment settings to application?

I am trying to deploy a Qooxdoo web application backed by CherryPy-hosted web services onto a server. However, I need to configure the client-side Qooxdoo application with the hostname of the server on which the application resides so that that the Ajax callbacks resolve to the right host. I have a feeling I can use the capabilities of the generate.py Qooxdoo script to generate client-side code with this appropriately set, but reading through the docs hasn't helped make it clear how yet. Anyone have any tips?
(FWIW, I know how I'd approach this using something like PHP and a different client-side framework like Echo 3--I'd have the index file be a PHP file that reads a local system configuration file prior to sending back client-side code. In this case, however, the generate.py file is a necessary part of the toolchain, so I can't see how to do it so simply.)
You can use qx.core.Enviroment class to add/get configuration for your project. The recommend way is only during compilation time, but there is a hack if you want to configure your application during run time.
Configuration during compilation time
If you want to configure the environment during compilation time see this.
In both cases after you add any environmental variable to your application, it can be accessed using the qx.core.Environment.get method.
On run time
WARNING this method isn't supported/documented from qooxdoo. Basically it's a hack
If you want to make available some environment configuration on run time you have to do this before qooxdoo loads. In order to this you could add some javascript into your webpage e.g.
window.qx = { };
window.qx.$$environment = {
"myawsomeapp.hostname": "example.org",
};
This should be added somewhere in your page before the qooxdoo start loading otherwise it will not have the desirable effect. The advantage of this method is that you can push configuration to the client e.g. some api keys that may be different between instances of your application.
The easiest way will be to compose your AJAX URL on the fly from window.location; ideally, you would be able to use window.location.origin which for this StackOverflow website would be "https://stackoverflow.com" but there are issues with that on IE.
A cross platform solution is:
var urlRoot = window.location.protocol + "//" +
window.location.hostname + (window.location.port ? ':' +
window.location.port: '');
This means your URL will always be correct, even if the server name changes (eg your on a test server instead of production).
See here for more details:
https://tosbourn.com/a-fix-for-window-location-origin-in-internet-explorer/

Scrape website for basic data using Angular JS ( facebook like Link sharing module)

I am trying to make Facebook like "Link sharing" module i.e when anyone write a link while doing new POST , it will automatically show some basic data from the website like in facebook...
I tried simple scraping using $http.get and it is working only if I install CORS extension in google chroome so the main issue I am facing with this approach is to make is working without using any plugin for it...
I also tried by adding headers in config file but still no luck.
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
Please share me the best approach to do this feature or if there is any way I can solve CORS issue ?
Thanks
Zeshan
This is not possible. CORS exists for a reason: to STOP you from accessing HTTP resources from other domains without those other domains explicitly allowing you to.
Again: this is not possible due to security restrictions imposed by browsers.
The only way you can accomplish this, and the way Facebook does it, is to move those cross-domain requests to a server, where there are no cross-domain restrictions.
So $http.post('/some-script-on-my-server') where that script does the actual HTTP request for the remote page, scrapes the necessary information and returns it back to the browser.
There is a workaround for this in order to have an only browser working javascript solution without configuring anything in the server (maybe useful in some particular situation) and "avoiding" CORS.
You could use the YQL. This way you only have to play in their console a little bit with the url you need to scrape and use the query they provide you with in your website as url for your request.
For example (extracted from YQL website):
select * from html where url='http://finance.yahoo.com/q?s=yhoo' and xpath='//div[#id="yfi_headlines"]/div[2]/ul/li/a'
Gets the headlines from yahoo finance, and you get also the query url that you can use in your request:
https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D'http%3A%2F%2Ffinance.yahoo.com%2Fq%3Fs%3Dyhoo'%20and%20xpath%3D'%2F%2Fdiv%5B%40id%3D%22yfi_headlines%22%5D%2Fdiv%5B2%5D%2Ful%2Fli%2Fa'&format=json&diagnostics=true&callback=
They have other examples and how to integrate it in their documentation.
You don't need to configure anything in the server side, but of course, it has to go through Yahoo's, which isn't at all optimal. Of course, performance gets directly affected...
As said again, maybe in some particular situations (dev, tests, etc) this can be useful and it is always interesting to give it a try.

How to use Bedework server as a service for another system

For my application I need to use an open source calendar server. After some research I selected Bedework Server for my task. Basically what I want is to use this server to handle my application's calendar events. Even though I have setup a local server using quick start package, I kinda still confused on how I can use this. I can create events using it's web UI. But I want to use this as a service from my server (Something like a REST service). I read their documentation but I could not find anything that will help. I am really grateful if you can help me on this. Thanks in advance.
You can access the server using the CalDAV protocol. This is a standard REST protocol which specifies how you create/query/delete events and todos. It is the same protocol the Calendar or Reminders apps on OS X and iOS use to talk to the server.
The CalConnect CalDAV website is a good entry point to learn more about this.
If you are still looking this, you can try using any CalDAV Client Libraries -
CalDAV-libraries
I tried CalDAV4j library. For all basic use cases, it works fine.
There is also a demo github project on this library developed to list down the events in the server -
list-events-caldav4j-example
You can make use of the ListCalendarTest.java in the project and give appropriate endpoints to the Host configuration. For Example (for Bedework) -
HttpClient httpClient = new HttpClient();
// I tried it with zimbra - but I had no luck using google calendar
httpClient.getHostConfiguration().setHost("localhost", 8080, "http");
String username = "vbede";
UsernamePasswordCredentials httpCredentials = new UsernamePasswordCredentials(username, "bedework");
...
...
CalDAVCollection collection = new CalDAVCollection("/ucaldav/user/" + username + "/calendar",
(HostConfiguration) httpClient.getHostConfiguration().clone(), new CalDAV4JMethodFactory(),
CalDAVConstants.PROC_ID_DEFAULT);
...
...
GenerateQuery gq = new GenerateQuery();
// TODO you might want to adjust the date
gq.setFilter("VEVENT [20131001T000000Z;20131010T000000Z] : STATUS!=CANCELLED");
CalendarQuery calendarQuery = gq.generate();

Does the GCE/Eclipse magic add client IDs automagically?

Or put another way...
I just moved my app from aaa.appspot.com to a new project (and hence new Client ID) called bbb.appspot.com. When I went to add the new Client Id to my GCE API definitions, it was already there!
So, on the one hand, it's magic :-)
On the other hand, is all of this documented anywhere? I have a slight concern about how I would go about overriding this behaviour if ever I want to manually configure the permitted client IDs.
I assume you are talking about the API annotations for GCE like this:
#ApiMethod(
name = "testAuth",
clientIds = { WEB_CLIENT_ID,
APP1_ANDROID_CLIENT_ID, APP1D_ANDROID_CLIENT_ID,
APP2_ANDROID_CLIENT_ID },
audiences = { Config.WEB_CLIENT_ID }
)
These client ID's come from the API console, where they are created based on your app's package and the hash of your app's certificate.
So, you may create a new GAE project for your new app id, and even create a new console project connected to that new GAE project, but your old console project still exists and still has client id's that are specific to your Android project but independent of your GAE project - so they still work.

Resources