Keycloak is missing port in OpenID config response - keycloak

These one seems odd. When I fetch the OpenID config via Postman or in the browser, I get a valid config response.
For example a GET via Postman or in the browser to
http://127.0.0.1:8080/auth/realms/myrealm/.well-known/openid-configuration
returns the endpoint including the port 8080 correctly:
{
snip
"jwks_uri": "http://127.0.0.1:8080/auth/realms/myrealm/protocol/openid-connect/certs"
snip
}
However, fetching the from the very same host, target, port, scheme (http) in my C++ application returns the confi endpoints all without a port (e.g. 8080 is missing)
{
snip
"jwks_uri":"http://127.0.0.1/auth/realms/myrealm/protocol/openid-connect/certs"
snip
}
I do not see any issue in my C++ client code, I'm not sure what's making the difference at all. For completeness, this is the C++ code I'm using next to actual values when sending the request, though that should not really be a matter of programming language used:
req_.version(version); // HTTP 1.1
req_.method(method); // GET
req_.target(target); // /auth/realms/myrealm/.well-known/openid-configuration
req_.set(http::field::host, host); // 127.0.0.1
static const std::string agent = app.myAgent();
req_.set(http::field::user_agent, agent);
req_.set(http::field::content_type, contentType); // application/json
I have two questions here:
1) What causes Keycloak not to add the port to the endpoints? And how to workaround it?
2) What's making the difference between the calls? This should be a vanilla GET request.

Figured it out. According to the HTTP spec the port must be included in the host name if it's not a default name:
https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.23
That resolved the issue. Though, my opinion is it should be fixed in Keycloak as well. I would expect static URLs and not something that changes depending on your request. For an example, you could set host to localhost during request and it will return "localhost" in the config, set it to 127.0.0.1 and it will return that. What will it return for an actual IP when queried locally, but the server has a public IP? I didn't try that but it seems odd enough.

Related

GWT with http loadbalancer gives invalid SID value

I have 2 openfire servers and an elastic loadbalancer over them and built a gwt application that using http bind at port 7070
when connecting directly to one server it works good but when it connects to the loadbalancer on port 7070 it’s not working and output an error with 404 invalid SID value
Note:
When the load balancer is working at tcp mode it works fine but when its http mode it doesn’t work and i need to make a sticky session for it
That's because once BOSH session is established on one machine then it's tied to this machine. Without enabling sticky session on the ELB subsequent requests from the client can be routed to the second server, on which there is no BOSH session that maches the request, which in turn results in invalid SID (because SID doesn't exist on the other machine).
Alternative solution would be (if the machines would also expose public IP) to return "host" information in the BOSH response therefore client could use that information and then make subsequent requests to correct machine. But if that's not possible, they ou have to use "sticky session".

Socket IO using Cloudflare gives 404s for /socket.io/?EIO=3&transport=polling&t=M8UDUNL

I am working on a node.js site that uses socket.io on ports 8443 and port 443. The site works locally as well as using namecheap for dns records pointing to the production server. I recently set the nameservers to Cloudflare and added the same A record there that I was using at namecheap. Now everything works except for the socket.io to port 443. Requests using port 443 that are not using socket.io are working fine.
I am getting this error:
GET https://<domain>/socket.io/?EIO=3&transport=polling&t=M8UDaUZ 404 ()
Port 8443 socket.io requests are getting 200 responses, and include an sid:
https://<domain>:8443/socket.io/?EIO=3&transport=polling&t=M8UDUTx&sid=cuq1LLdLLVSj2F4FAAAN
I am not sure if the sid missing on the port 443 requests indicates the problem. When I asked cloudflare support about it, their response was 404 means to check the path.
The only thing that has changed is the DNS so I don't think this can be a path problem or a code problem with the site. It seems like it has to be something Cloudflare is doing differently than namecheap for dns or socket.io connections.
I don't see any other errors. Does anyone know what the problem could be or how to fix it for Cloudflare?
Have you managed to solve the issue?
I was dealing with the same issue (or looked the same) and what helped me was setting sockets.io listen to HTTP server.
Server code:
var http = require('http');
var server = https.createServer(app).listen(80, function() {
console.log('Express HTTP server listening');
});
var io = require('socket.io').listen(server);
var secureServer = https.createServer(httpsOptions, app);
console.log('Express HTTPS server listening');
});
Client uses wss:// (so transport is secure).
Also I have CloudFlare option "proxy all HTTP to HTTPS" enabled.

How to connect to a SVC endpoint?

Given a URL that ends with .svc and that is supposed to run a SOAP web service, how can I get some data from it?
I tried:
to access it via a web browser
to access it via the Python's library Zeep
to access it via the Microsoft utilitary svcutil.exe
In all cases, I get a timeout error:
Failed to establish a new connection: [Errno 10060] A connection attempt failed because the connected party did not properly respond after a period of time.
Does it mean that the web service does not work, or that I do things the wrong way?
Importantly - there is a big distinction between "service not active" (and by that I mean no listener on port 80), and "port not open in firewall".
If the problem were simply that you didn't have a service listening on port 80, you would have gotten something like "connection reset" or "connection rejected" as an error.
Instead, you appear to have gotten a timeout, which implies that either the SYN from the client doesn't reach the server, or the SYN/ACK from the server doesn't reach the client. [ You could verify this by doing a packet capture for port 80 on both client and server ]
I would be tempted to check any firewall in front of the server to see that it's letting port 80 traffic through from your client.
Diagnosing Connectivity Issues
Without more details it is difficult to say, but given your timeout error:
Failed to establish a new connection: [Errno 10060] A connection attempt failed because the connected party did not properly respond after a period of time.
This indicates a network connectivity error at the TCP level, so it is likely web service is not active on the port your are using (default of 80 for http, 443 for https).
In a comment you said you pinged the URL and it responded normally - I assume this means you pinged the hostname. If this is responding normally it means the server is active, but that doesn't tell you anything about the availability of the web service on that server.
telnet %hostname% %port%
where %port% is 80 for http or 443 for https, or something else if there is a port number in the URL you are using (e.g. http://somehost.somewhere.com:port/path.scv)
If ping works and telnet does not connect, then the service is not active.
I suspect this is the case. If the service was active and it was simply that you requesting the data incorrectly, I believe you'd get a different error message - e.g. a valid HTTP response with status code 500 or 404 or similar.
Getting Data from a Web Service
As to your original question as to how to get data from it - once you verify that the service is active, the method to get the data will depend on the specification of the service - i.e.:
which HTTP methods (GET, POST, etc.) does it support
what parameters it requires
what format it requires the parameters in
are the parameters in the query string or POST body.
To interact with a web service there are many command line tools that can be used, as well as the options you have tried, including:
POSTMan Google Chrome Plugin
curl
wget
In windows Powershell, the Invoke-WebRequest
Getting Data from a SOAP Web Service
As you have said it is a SOAP web service, if you have the URL for the wsdl, you can often interract with it using Powershell SOAP WebService Proxies.
The wsdl location varies, but is often at a URL that looks something like.
http://host/path.svc?wsdl
http://host/path.svc/?wsdl
http://host/path/?wsdl
Also if it's configured correctly, just loading the URL in a browser will present a page with a link to the wsdl.
The general idea is:
$URI="http://hostname/path.svc?wsdl"
$Proxy = New-WebserviceProxy $URI –Namespace X
$Proxy | get-member -MemberType Method
This will return a list of methods on the proxy that you can invoke as powershell methods. Any types defined in the wsdl that are needed for arguments, or returned from methods will be available within the namespace X. Invoking the methods will proxy the request to the service, taking care of serializing parameters and serializing results into powershell objects.

How to send HTTP Commands through Port 80

Breif Description of what I am trying to accomplish. So I am working with Crestrons Simpl+ software. My job is to create a module for a sound masking system called QT Pro. Now, QT Pro has an API where you can control it via HTTP. I need a way to establish a connection with the QT Pro via HTTP( I have everything I need, IP, Username, Password).
Whats the problem? I have just started working with this language. Unfortunately there isn't as much documentation as I would like, otherwise I wouldn't be here. I know I need to create a socket connection via TCP on port 80. I just don't know what I'm supposed to send through it.
Here is an example:
http://username:password#address/cmd.htm?cmd=setOneZoneData&ZN=Value&mD=Value
&mN=Value&auxA=Value&auxB=Value&autoR=Value
If I were to put this into the URL box, and fill it in correctly. then it would change the values that I specify. Am I supposed to send the entire thing? Or just after cmd.htm? Or is there some other way I'm supposed to send data? I'd like to stay away from the TCP/IP Module so I can keep this all within the same module.
Thanks.
You send
GET /cmd.htm?cmd=setOneZoneData&ZN=Value&mD=Value&mN=Value&auxA=Value&auxB=Value&autoR=Value HTTP/1.1
Host: address
Connection: close
(End with a couple of newlines.)
If you need to use HTTP basic authentication, then also include a header like
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
where the gibberish is the base64-encoded version of username:password.
But surely there is some mechanism for opening HTTP connections already there for you? Just blindly throwing out headers like this and hoping the response is what you expect is not robust, to say the least.
To see what is going on with your requests and responses, a great tool is netcat (or telnet, for that matter.)
Do nc address 80 to connect to server address on port 80, then paste your HTTP request:
GET /cmd.htm HTTP/1.1
Host: address
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Connection: close
and see what comes back. SOMETHING should come back. (Remember to terminate with two newlines.)
To see what requests your browser is sending when you do something that works, you can listen like this: nc -l -p 8080.
Then direct your browser to localhost:8080 with the rest of the URL as before, and you'll see the request that was sent. (Then you can type back to see how the browser handles the response.)

Using Fiddler with IIS7 Express

I am using IIS7 Express while developing my web application. I need to use fiddler to investigate an issue and cannot figure out how to configure things so I can get the HTTP stream. It seems that IIS7 express will only listen on localhost which means I cannot access the stream.
This has nothing to do with IIS7 Express and everything to do with the fact that you're using loopback traffic.
Ref: https://www.fiddlerbook.com/fiddler/help/hookup.asp#Q-LocalTraffic
Click Rules > Customize Rules.
Update your Rules file like so:
static function OnBeforeRequest(oSession:Fiddler.Session)
{
if (oSession.HostnameIs("MYAPP")) { oSession.host = "localhost:portnumber"; }
}
Then, just visit http://myapp in your browser.
Or use the address http://localhost.fiddler/ and Fiddler will use the hostname localhost instead of converting to an IP address.
One useful variation of Eric's answer (that was edited by Brett) would be to use oSession.port to build the oSession.host. With this little change, if one needs to capture IIS express traffic on http://localhost:12345, they could use http://iisexpress:12345. That will make it easier to capture traffic for sites with random ports as created by WebMatrix and VS. I tried it out with IE and Firefox and capturing IIS Express traffic was a breeze. Fiddler rocks!.
static function OnBeforeRequest(oSession:Fiddler.Session)
{
//...
// workaround the iisexpress limitation
// URL http://iisexpress:port can be used for capturing IIS Express traffic
if (oSession.HostnameIs("iisexpress")) { oSession.host = "localhost:"+oSession.port; }
//...
}
With the latest version of fiddler, you only need to navigate to localhost.fiddler:port. However, doing that alone didn't help me and I was still getting access denied when using Windows Authentication. To fix this, I found this blog entry: http://www.parago.de/2013/01/fiddler-and-the-401-unauthorized-error-with-asp-net-web-api-using-integrated-windows-authentication-wia/
In short, create this key:
Key Path HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ Control\Lsa\MSV1_0
Value Name BackConnectionHostNames
Value Type REG_MULTI_SZ
String Value localhost.fiddler
You can use fiddler as a proxy between your clients and the server. This means you start up fiddler, and then access the server using fiddler's port rather then the usual port (default for fiddler2 is 8888 I think). If you need to debug the server "live" vs. real world clients, you can change the IIS binding from :80 to something else, and place fiddler's proxy on port 80.
EDIT: By the way, by default fiddler2 changes the proxy settings on your browsers so that they access everything through fiddler anyway (on the machine in which fiddler is installed only)