Load a webpage that requires basic authentication in a Windows 8 App - iframe

How would you load an external site that requires basic authentication inside an iframe in a Windows 8 HTML/JavaScript app?
I've found that you can't use URLs of the form http://username:password#host/.

In order to load the URL I was trying to load, I had to use a webview or x-ms-webview and invoke it's navigateWithHttpRequestMessage function in order to pass the basic authentication header.
This resulted in the following code structure:
function ready(element, options) {
var webview = document.querySelector('[data-hook~="camera"]');
webview.navigateWithHttpRequestMessage(buildRequest());
}
function buildRequest() {
var username = 'username',
password = 'password',
Crypto = Windows.Security.Cryptography,
Http = Windows.Web.Http,
request,
buffer,
token;
request = new Http.HttpRequestMessage(
Http.HttpMethod.get,
new Windows.Foundation.Uri('http://ipcamera/'));
buffer = Crypto.CryptographicBuffer.convertStringToBinary(
[username, password].join(':'),
Crypto.BinaryStringEncoding.utf8);
token = Crypto.CryptographicBuffer.encodeToBase64String(buffer);
request.headers.authorization = new Http.Headers.HttpCredentialsHeaderValue('basic', token);
return request;
}
The caveat to this is that none of the DOM ready events seem to fire, so if you need to interact with the external site, you'll have to play with timers.

Related

Using an asp web api in wpf

So i have got a simple question, when using our cms we can attach a driver as an executable.
The driver we want to make is an httpreceiver or just an api endpoint. SO i tought lets use asp.net web api for it -> using version .net 4.6.1. altough asp.net application requires a webserver and is not an executable, But i read on google you can use it inside a wpf application since our cms is wpf in the first place.
So my question is is there a way i can use my mvc web api project inside a wpf application? and if not what would be the best bet to have an httpreceiver or httppost receiver into an executable?
Main reason is we want to send httppost requests to the server as a desktop application. I know it's complicated but thats how it needs to be as far as I know.
In the case where asp is not an option, what the best way to make a postreqst/ httpreceiver as a desktop application?
EDit:
the resource guide from microsoft beneath was perfectly however i still have a question:
string baseAddress = "http://localhost:9000/";
// Start OWIN host
using (WebApp.Start<Startup>(url: baseAddress))
{
// Create HttpClient and make a request to api/values
HttpClient client = new HttpClient();
string username = "test".ToUpper().Trim();
string password = "test123";
//Mock data
var body = new PostTemplate1();
body.Description = "test";
body.StateDesc = "httpdriver/username";
body.TimeStamp = DateTime.Now;
body.Message = "This is a post test";
var json = JsonConvert.SerializeObject(body);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var authToken = Encoding.ASCII.GetBytes($"{username}:{password}");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authToken));
var response = await client.PostAsync(baseAddress + #"api/Post", data);
var result = response.StatusCode;
}
As the guide says you post to url with port 9000
is there a possibility to use another port and use https?
if yes where to manage certificates for handling https?

Problem using http GET request in flutter

So I got a template of a Flutter app that retrieves all its data from a website using HTTP get requests.
I have the following method that gets the list of resturaunts:
Future<Stream<Restaurant>> getNearRestaurants(LocationData myLocation, LocationData areaLocation) async {
String _nearParams = '';
String _orderLimitParam = '';
if (myLocation != null && areaLocation != null) {
_orderLimitParam = 'orderBy=area&limit=5';
_nearParams = '&myLon=${myLocation.longitude}&myLat=${myLocation.latitude}&areaLon=${areaLocation.longitude}&areaLat=${areaLocation.latitude}';
}
final String url = '${GlobalConfiguration().getString('api_base_url')}restaurants?$_nearParams&$_orderLimitParam';
final client = new http.Client();
final streamedRest = await client.send(http.Request('get', Uri.parse(url)));
return streamedRest.stream.transform(utf8.decoder).transform(json.decoder).map((data) => Helper.getData(data)).expand((data) => (data as List)).map((data) {
return Restaurant.fromJSON(data);
});
}
However when I swap the template's url variable for my own website, the app gets stuck since it cannot retrieve the same information from my website.
What could I be missing? Is the problem in the flutter code or the website?
Update 1:
I surrounded it with a try/catch block and it gave me a "bad certificate exception.". This might be because my website does not have a SSL certificate, so I added an exception to the HttpClient for my self-certified website:
bool _certificateCheck(X509Certificate cert, String host, int port) =>
host == '<domain>';
HttpClient client2 = new HttpClient()..badCertificateCallback = (_certificateCheck);
HttpClientRequest request = await client2.getUrl(Uri.parse(url));
var response = await request.close(); // sends the request
// transforms and prints the response
response.transform(Utf8Decoder()).listen(print);
This code showed a Error 404: Not found on the page that I need to get my JSON data from.
I also installed postman and checked my website with the GET statement for the same list of restaurants I try to retrieve in the flutter code posted above and see this:
Postman GET screenshot
Update 2:
So I configured SSL on my website and the problem still persists. I tried testing the GET request via postman and it returns a error 404 page as well. I have tried going through my server files and laravel logs and nothing did the trick.
Its as if my website cannot route to the specific pages in my API folder. BUt they are all defined in api.php.

ADFS Single sign on is not working with session state mode "UserUri"

Our asp.net website was working fine with ADFS SSO since we made a change in the session state cookie settings from "Use Cookies" to "USE URI". After making this change, fam.IsSignInResponse(request) is always false in the below code so that it redirects back to the ADFS login screen recursively.
public List<ClaimEntity> GetClaims()
{
logger.Info("Started executing GetClaims()");
List<ClaimEntity> claims = new List<ClaimEntity>();
// sam is configured in web.config
var sam = FederatedAuthentication.SessionAuthenticationModule;
logger.Info("Declaring sam");
// fam is not
var fam = new WSFederationAuthenticationModule();
logger.Info("Declaring fam");
//fam.FederationConfiguration = FederatedAuthentication.FederationConfiguration;
fam.ServiceConfiguration = FederatedAuthentication.ServiceConfiguration;
logger.Info("Assigning ServiceConfiguration to fam");
var request = thisContext.Request;
// is this the response from the STS
if (!fam.IsSignInResponse(request))
{
// no
logger.Info("fam.IsSignInResponse => No");
// the STS
fam.Issuer = _IssuerSTSSpec.Issuer;
logger.Info("IssuerUrl= " + _IssuerSTSSpec.Issuer);
// the return address
fam.Realm = thisContext.Request.Url.AbsoluteUri;
logger.Info("Assigning fam.Realm= " + thisContext.Request.Url.AbsoluteUri);
logger.Info("Creating SignInRequest...");
var req = fam.CreateSignInRequest(string.Empty, null, false);
logger.Info("Redirecting to the issuer...");
logger.Info("Request to STS: "+ req.WriteQueryString().ToString());
// go to STS
thisContext.Response.Redirect(req.WriteQueryString());
}
else
{
// yes
-----------
-----------
}
logger.Info("Returning the claims");
return claims;
}
Is "USE URI" session cookie mode is not supported with ADFS integrated application or any changes required in my code?
It would help understand better if you add the example code of "Use URI".
Is there really a need to use this method?
Using cookies will keep the URL clean and it is more manageable. And if it is already working for you, you can go with it unless there is really need to use URI

DDP.connect and Meteor.users

I am in the process to try to separate out the mobile from the desktop part of my application and thought I try DDP.connect as a means for the mobile application to share data with the desktop application.
My first hurdle is concerning Meteor internal collections and publications.
How am I supposed to authenticate users? I know I can call the login method to authenticate a user, but that still doesn't give me all the other nice reactive features I am used to with Meteor.users
Is this supposed to work, and if so what is the pattern.
Thanks
This is what integrated completely with a remote server (except code refresh, which forgets user session)
if (Meteor.isClient) {
Meteor.connection = DDP.connect('http://remote.site.com');
Accounts.connection = Meteor.connection;
Meteor.users = new Meteor.Collection('users');
SomeCollection = new Meteor.Collection('remote_collection');
Meteor.connection.subscribe('users');
Meteor.connection.subscribe('remote_collection');
// rest if the code just as always
}
This way you can use login directly (via accounts-base, accounts-passed, etc) and don't need to call a login method. Just add accounts-ui and include {{>loginButtons}} and it works
I had a similar problem. I wanted to have two different front-ends (although both are for desktop) to the same back-end, so they could use same database, publications, and methods. After looking through Meteor's source code (version 1.1.0.3) I've managed to do this as follows.
1) Start back-end server project.
$ meteor --port 3100
2) In front-end project(s), put following in server/server.config.js.
var backendUrl = process.env.BACKEND_URL;
if (backendUrl) {
__meteor_runtime_config__.BACKEND_URL = backendUrl;
__meteor_runtime_config__.ACCOUNTS_CONNECTION_URL = backendUrl;
console.log('config', __meteor_runtime_config__);
}
3) In front-end project(s), put following in client/lib/client.connection.js. APS is just a namespace for my application. Be sure to have this loaded before you use subscriptions or methods (that's why it's in lib folder).
if (typeof APS == 'undefined') APS = {};
var backendUrl = __meteor_runtime_config__.BACKEND_URL;
if (backendUrl) {
APS.backendConnection = DDP.connect(backendUrl);
Meteor.connection = APS.backendConnection;
_.each(['subscribe', 'methods', 'call', 'apply', 'status', 'reconnect', 'disconnect'], function(name) {
Meteor[name] = _.bind(Meteor.connection[name], Meteor.connection);
});
console.log('connected to backend', APS.backendConnection);
}
4) Start front-end server with BACKEND_URL environment variable pointing to your back-end server.
$ BACKEND_URL=http://192.168.33.10:3100 meteor
That's all. Refresh on client works OK. And we don't have to fiddle with Accounts.*.
UPDATE: Just found a problem with my solution. When calling server methods, this.userId is always null. This is because Meteor.connection and Accounts.connection were two separate connections, despite to the same BACKEND_URL. Upon authentication, user ID gets associated only with the latter. Fixed client.connection.js is as follows.
if (typeof APS == 'undefined') APS = {};
var backendUrl = __meteor_runtime_config__.BACKEND_URL;
if (backendUrl) {
APS.originalConnection = Meteor.connection;
// Accounts is already connected to our BACKEND_URL
APS.backendConnection = Accounts.connection;
// Reusing same (authenticated) connection for method calls and subscriptions
Meteor.connection = APS.backendConnection;
_.each(['subscribe', 'methods', 'call', 'apply', 'status', 'reconnect', 'disconnect'], function(name) {
Meteor[name] = _.bind(Meteor.connection[name], Meteor.connection);
});
console.log('Connected to backend', APS.backendConnection);
}
You can authenticate using code like this:
var connection = DDP.connect("<url>")
To authenticate
connection.call("login", {"password":"qwerty","user":{"username":"user_1"}});
to get the user, add this on the other server)
Meteor.methods({
whoami: function() { return Meteor.user() }
});
Then you can run further commands as if you were authenticated, like this to get who's logged in
console.log(connection.call("whoami");
User account creation/Authentication:
In client.js, create a DDP connection and set it to Accounts.connection
Accounts.connection = Meteor.remoteConnection;
Create an Accounts.users collection in the client and subscribe its contents from the external server as below.
Accounts.users = new Meteor.Collection('users', {connection: Meteor.remoteConnection});
Meteor.remoteConnection.subscribe('users');
Now call the login method required as below and set the token returned in the localStorage. This works for all the internal clicks and routing.
Meteor.loginWithPassword(login_email, login_password, function(err) {
submit_button.button("reset");
if (err)
{
console.log(err);
pageSession.set("errorMessage", err.message);
return false;
}else{
console.log("logged in as "+Meteor.userId());
var token = Accounts._storedLoginToken();
localStorage.setItem('_storedLoginToken', token);
}
});
The problem with the above code is that, the token is reset after every manual client refresh. The result object contains the below signed in information. We have to take the token and login with token for every external client refresh.
id:"5RigABaSzbARHv9ZD"
token:"MItg8P59gsl_T5OXtaWRSjUnETqzns0hGEV26xWYxj7"
tokenExpires:Thu Jul 20 2017 12:46:31 GMT+0530 (India Standard Time)
In client.js, start-up call the loginwithtoken function with the returned token as below, whenever there is no user available.
var user = Meteor.user();
var token = localStorage.getItem('_storedLoginToken');
if(user==null){
console.log("Token"+token +user);
if(token)
Meteor.loginWithToken(token, function(err){
// this is going to throw error if we logged out
if(!err) {
console.log('logged in !!!! ',token);
}
});
}
Meteor throws an error while logging in with the token,
Error logging in with token: Error: You've been logged out by the server. Please log in again. [403]
To overcome this issue, we have to write a tracker function to track the logged in session and login again if required. This is basically a hack suggested in meteor forums.
Tracker.autorun(function () { var user = Meteor.user(); var token
= localStorage.getItem('_storedLoginToken'); if(user==null){ console.log("Token"+token +user); if(token)
Meteor.loginWithToken(token, function(err){
// this is going to throw error if we logged out
if(!err) {
console.log('logged in !!!! ',token); }
}); } });
Reset the localStorage if user navigates to the login path. In Layout.js,
if(path=='/login')
localStorage.setItem('_storedLoginToken',null);

Google OpenId Connect migration: getting the openid_id in ASP.NET app

I've gone through plenty of Google documentation and SO Q/A's but with no luck. I wonder if anyone has yet succesfully used the OpenId to OpenId Connect migration as advised by Google.
This is what we used to do:
IAuthenticationResponse response = _openid.GetResponse();
if (response != null) {
//omitted for brevity
} else {
IAuthenticationRequest req = _openid.CreateRequest("https://www.google.com/accounts/o8/id");
req.AddExtension(new ClaimsRequest
{
Country = DemandLevel.Request,
Email = DemandLevel.Request,
Gender = DemandLevel.Require,
PostalCode = DemandLevel.Require,
TimeZone = DemandLevel.Require
});
req.RedirectToProvider();
}
That was done using a version of DotNetOpenAuth that dates back a few years. Because Google has deprecated OpenId authentication we are trying to move over to OpenID Connect. The key question here is: can I somehow get my hands on the OpenId identifier (in the form of https://www.google.com/accounts/o8/id?id=xyz) using the latest version of DotNetOpenAuth library or by any other means?
I have tried the latest DotNetOpenAuth and I can get it to work but it gives me a new Id (this was expected). I have also tried the Javascript way by using this URL (line breaks for readibility):
https://accounts.google.com/o/oauth2/auth?
scope=openid%20profile%20email
&openid.realm=http://localhost/palkkac/
&client_id=//here is the client id I created in google developer console
&redirect_uri=http://localhost/palkkac/someaspxpagehere
&response_type=id_token%20token
I checked (using Fiddler) the realm value that we currently send using the old DotNetOpenAuth code and it is http://localhost/palkkac/. I've put the same realm in the url above. The redirect url starts with the realm value but it is not entirely the same.
When I redirect to a simple page that parses the id_token and decrypts it (using the https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=zyx endpoint) I get this:
audience "client id is here"
email "mikkark#gmail.com"
expires_in 3597
issued_at //some numbers here
issued_to "client id is here"
issuer "accounts.google.com"
user_id "here is a sequence of numbers, my id in the OpenID Connect format that is"
verified_email true
So there is no sign of the openid_id field that you would expect to find here, though the whole structure of the message seems different from the Google docs, there is no field titled sub, for example. I wonder if I'm actually using the wrong endpoint, parameters or something?
What I have been reading is the migration guide: https://developers.google.com/accounts/docs/OpenID. I skipped step 2 because it seemed like an optional step. In step 3 the field openid_id is discussed and I would like to get that to work as a proof-of-concept first.
We registered the app on Google in order to create the client id etc. There are now also numerous allowed redirect url's as well as javascript origins listed in the Google dev console. Let me know if those might mess up the system and I'll post them here for review.
Side note: we are supposed to be moving our app behind a strictly firewalled environment where we would need to open ports in order to do this on the server side. Therefore, a client-side Javascript solution to access Google combined with HTTPS and redirecting the result to the server would be prefered (unless there are other issues that speak against this).
There are other resources on SO regarding this same issue, although all of these seem to use different libraries on the server side to do the job and nobody seems to have made any attempts at using Javascript:
Here (https://stackoverflow.com/questions/22842475/migrating-google-openid-to-openid-connect-openid-id-does-not-match) I think the problem was resolved by setting the realm to be the same as in the old OpenId2.0 flow. This does not seem to work in my case.
over here the openid_id field is also missing, but the problem here is more about how to request the id_token from Google using libraries other than DotNetOpenAuth.
and in here there seem to be similar problems getting Google to return the openid_id field.
You can use the GoogleAuthentication owin middleware.
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions
{
SignInAsAuthenticationType = signAs,
AuthenticationType = "Google",
ClientId = "xxx.apps.googleusercontent.com",
ClientSecret = "xx",
CallbackPath = PathString.FromUriComponent("/oauth2callback"),
Provider = new GoogleOAuth2AuthenticationProvider
{
OnApplyRedirect = context =>
{
context.Response.Redirect(context.RedirectUri + "&openid.realm=https://mydomain.com/"); // DotNetOpenAuth by default add a trailing slash, it must be exactly the same as before
}
},
BackchannelHttpHandler = new MyWebRequestHandler()
}
Then, add a new class called MyWebRequestHandler:
public class MyWebRequestHandler : WebRequestHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var httpResponse = await base.SendAsync(request, cancellationToken);
if (request.RequestUri == new Uri("https://www.googleapis.com/plus/v1/people/me")) return httpResponse;
var configuration = await OpenIdConnectConfigurationRetriever.GetAsync("https://accounts.google.com/.well-known/openid-configuration", cancellationToken); // read the configuration to get the signing tokens (todo should be cached or hard coded)
// google is unclear as the openid_id is not in the access_token but in the id_token
// as the middleware dot not expose the id_token we need to parse it again
var jwt = httpResponse.Content.ReadAsStringAsync().Result;
JObject response = JObject.Parse(jwt);
string idToken = response.Value<string>((object)"id_token");
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
try
{
SecurityToken token;
var claims = tokenHandler.ValidateToken(idToken, new TokenValidationParameters()
{
ValidAudience = "xxx.apps.googleusercontent.com",
ValidIssuer = "accounts.google.com",
IssuerSigningTokens = configuration.SigningTokens
}, out token);
var claim = claims.FindFirst("openid_id");
// claim.Value will contain the old openid identifier
if (claim != null) Debug.WriteLine(claim.Value);
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
return httpResponse;
}
}
If like me you found this not really straightforward, please help by upvoting this issue https://katanaproject.codeplex.com/workitem/359

Resources