Identity Server 4 Failed to Validate the Token from localhost for the protected API - identityserver4

Scenario
localhost & 192.168.0.10 refer to the same machine called MyPC
Identity server is running on that "MyPC"
UI uses "localhost" to communicate with Identity Server
The protected API uses "192.168.0.10" to communicate with Identity Server
UI & API talk to each other and authenticated by an Identity Server
In the above scenario, If I use Identity Server 3, everything is fine; however the problem started when I switch to Identity Server 4 (the latest version). I got this error in the API
System.IdentityModel.Tokens.SecurityTokenInvalidIssuerException: IDX10205: Issuer validation failed. Issuer: 'localhost:9987'......
That error will go away if I use the same IP address (localhost or 192.168.0.10) for both UI & API to communicate with the Identity Server.
Could anyone point me to the direction to fix this? I do need the ability to access Identity Server using either 127.0.0.1, localhost, Lan Addresses, Wan Addresses?
This is code that I am using in the API Startup:
services.AddAuthentication(o =>
{
o.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
o.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
})
.AddIdentityServerAuthentication(x =>
{
x.Authority = Configuration.GetSection("URL").GetSection("IdentityServerURL").Value;
x.ApiSecret = Configuration.GetSection("Resource").GetSection("APISecrets").Value;
x.ApiName = Configuration.GetSection("Resource").GetSection("APIName").Value;
x.SupportedTokens = SupportedTokens.Both;
x.RequireHttpsMetadata = false;
});
P/S: I had done research on this but there wasn't any clear answer on this.

The IdentityServer4 server will include an "Issuer" in the JWT token. You can double check e.g. using jwt.io what that is. From the relevant docs:
Set the issuer name that will appear in the discovery document and the issued JWT tokens. It is recommended to not set this property, which infers the issuer name from the host name that is used by the clients.
If you do custom naming, aliasing, ports, subdomains, and whatnot, then you could go ahead and set it manually anyways (both on the server side and on the validation side), or set issuer validation off (perhaps only in dev) altogether.

Related

Co-hosting Identity Server 4 with API services using Roles

I've come across an example of co-hosting Identity Server 4 on the same App Host as the API Services that need it for authentication and authorization.
Now I was able to replicate this successfully by just pure authentication but when it comes to authorization using Roles I couldn't get it to work, i.e. adding the [Authorize(Roles = "My Role")] attribute on my Controller Action.
The access token contains the "role" scope and claim but it doesn't seem to be respected at all.
I initially tried the code below but it doesn't execute the JWT Bearer bit at all which leads me to believe that Identity Server uses its own handler for that purpose and I have no idea how to configure it if at all.
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
// JWT tokens (default scheme)
.AddJwtBearer(options =>
{
options.Authority = "https://localhost:44367/";
options.Audience = "API";
options.TokenValidationParameters.RoleClaimType = "role";
});
Then I came across this line from the example code (I mentioned initially in this post) which seems like its supposed to grant me the ability to run API services along side with Identity Server:
services.AddLocalApiAuthentication();
But it also doesn't seem to do what I want.
So does the Identity Server authentication middleware allow me to accomplish role-based authentication or is there some other mechanism (i.e. Policies) that I need to look into?
Something worth noting, I was able to accomplish all of this successfully with Identity Server 4 but by hosting it all separately. I want to see what it takes to host it all together.
Just rechecked the example and it worked perfectly fine.
When you use
services.AddLocalApiAuthentication();
it sets up the IdentityServerAccessToken authenticationScheme.
To use it in your API controller you type
[Authorize(IdentityServerConstants.LocalApi.PolicyName)]
as described in the doc, or just
[Authorize(AuthenticationSchemes = "IdentityServerAccessToken")]
All you need to check the roles is one more argument for the attribute:
[Authorize(AuthenticationSchemes = "IdentityServerAccessToken", Roles = "test role1")]

reactJs secure storage

I'm a back-end developer who has to create the front-end too in the current project!
I'm using reactJs and I know that for authorizing users I should get an api_token from my back-end API then use the api_token in the next requests! so I should store the api_token (actually somewhere into the client's browser)! but where should I store it to be secure?
the first answer came to my mind was 'Local Storage' ! but I've read this article: Don't store tokens in local storage
I've searched and found #auth0/auth0-spa-js, but I don't know can I trust this package (and similar) or not?
these are the way's which I've found! but what's the correct way to store sensitive data like this?
The Auth Flow should be on the Web should be
Send User/Password Details to server
Server validates and returns encrypted token with some details inside and that's stored as a HTTP Cookie
Setup Protected endpoints so only users with token can access them
Security : HTTP Cookie only means that the browser doesn't have access to it on the client, only the server. But someone can simply just Copy Paste it into their cookies which if you're worried about or working on sensitive stuff, you will need to implement additional security measures such as the ones mentioned.
Generally, Device Management is not a web concern but you can also some validation on the token for things like make the token expire in 5 minutes, or expire on session end, DeviceId, Browser Id, IP address, send them an email that a new unknown IP has logged in, etc.
Never store private tokens in your frontend code
You should create a server that can only be accessed from a particular url (the url of your app). This server can have the secret tokens that you need to make calls. The that server can forward requests to the services you will use that need private tokens.

The reply address does not match the reply addresses configured for the application

SOLVED: For other people having this error, please check this:
I configured my endpoint/reply address as http:// whilst my app was running https://.. After changing it to https things worked as expected and I could login on the v2 endpoint as well as query the graph api.
It's also a restriction on the v2 endpoint, so beware of that. It just needs to be in https, see the docs:
Restrictions on redirect URIs
Currently, apps that are registered in the Application Registration Portal are restricted to a limited set of redirect URI values. The redirect URI for web apps and services must begin with the scheme https.
source: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-limitations
I have configured an application via the apps.dev.microsoft.com portal as described in this sample project.
I was running under a different port though, so when I set up the URLs in the app registrations I changed them to match my port number.
Now I'm receiving this error after the flow is trying to connect back to my application.
How can I debug this, or how do I know what is happening?
Additional technical information:
Correlation ID: 145d8f37-7229-4dce-8ace-c777e4aeef94
Timestamp: 2017-11-02 08:41:21Z
AADSTS50011: The reply address 'http://localhost:60761/signin-oidc'
does not match the reply addresses configured for the
application: '8b640f9d-e7d8-4c41-8a40-15069f5712ee'.
More details: not specified
I also get the notification that this application will be fed to the Azure AD Portal (app registrations) - but I can't find it there.

CXF WS-Trust service certificate configuration

Objective: Get information (using Apache CXF) from a third party (thus no control or access to the service backend) web service
which use WS-Trust i.e. it authenticates the user using a Secure Token Service in this case with UsernameToken authentication.
I have spent a LONG time trying to learn about the WS-* security standards and at the same time trying out different frameworks and
tools (Axis, Apache CXF, METRO with NetBeans, Microsoft .net, SoapUI plugin for Eclipse etc.) to connect to a specific service in
the cloud. I am trying to develop a backend client that fetch information from the service. Apache CXF is attractive here
because it seems to be the only Java framework which does not assume that everyone connecting to web services use clients deployed on a web application server.
The service providers have provided the necessary certificates and user credentials to connect to the service using STS.
They have also provided a detailed user guide using NetBeans and METRO to create a web application that is deployed on a GlassFish server.
I have followed this guide and managed to get data from the web service. Conclusion so far: The certificates are valid.
There are three certificates stored in a keystore (including chains):
webservice-encryption-certificate.cer (keystore alias: webservice-encryption)
token-signing-certificate.cer (keystore alias:
token-signing)
token-encryption-certificate.cer (keystore alias: token-encryption)
=================================================================
NetBeans configuration:
Service client:
Keystore -> token-signing-certificate.cer
Truststore -> webservice-encryption-certificate.cer
STS client:
Truststore -> token-encryption-certificate.cer
Username -> user
Password -> xxx
=================================================================
THE BIG QUESTION: How can I make a similar configuration in CXF as in NetBeans?
I'm using CXF version: 3.0.2
"Translating" this to CXF gives me the follownig exception:
WARNING: Interceptor for {http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice}SecurityTokenService#{http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice}Trust13IssueAsync has thrown exception, unwinding now
org.apache.cxf.binding.soap.SoapFault: The signature or decryption was invalid
at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.createSoapFault(WSS4JInInterceptor.java:841)
Here is what i tried in CXF (amongst MANY other things):
MyService service = new MyService(); // Stub created from WSDL (real service name has been renamed to MyService)
MyServiceInterface port = service.getPort();
org.apache.cxf.endpoint.Client client = ClientProxy.getClient(port);
Bus bus = ((EndpointImpl) client.getEndpoint()).getBus();
STSClient stsClient = new STSClient(bus);
stsClient.setWsdlLocation("https://login.some-domain.com/adfs/services/trust/mex"); // Web service is using ADFS 2.0 with MEX
stsClient.setServiceQName(new QName("http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice", "SecurityTokenService"));
stsClient.setEndpointQName(new QName("http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice", "UserNameWSTrustBinding_IWSTrust13Async"));
stsClient.setSendRenewing(false);
stsClient.getRequestContext().put("ws-security.sts.token.properties", "clientTruststore.properties");
stsClient.getRequestContext().put("ws-security.sts.token.username", "webservice-encryption"); // MOST LIKELY WRONG - WHERE DO I PUT THIS CERTIFICATE?
Map<String, Object> ctx = ((BindingProvider) port).getRequestContext();
ctx.put("ws-security.sts.prefer-wsmex", true); // If set to false some policies will not be satisfied
ctx.put("ws-security.username", "user"); // REQUIRED OR FAIL WITH: No username available
ctx.put("ws-security.password", "xxx"); // REQUIRED OR FAIL: No username available
ctx.put("ws-security.encryption.properties", "clientTruststore.properties"); // REQUIRED OR FAIL WITH: A encryption username needs to be declared
ctx.put("ws-security.encryption.username", "token-encryption"); // REQUIRED OR FAIL WITH: A encryption username needs to be declared
ctx.put("ws-security.signature.properties", "clientTruststore.properties");
ctx.put("ws-security.signature.username", "token-signing");
ctx.put("ws-security.is-bsp-compliant", "false");
ctx.put("ws-security.sts.client", stsClient);
port.callSomething(createMyRequestObject());
I have tried to "decrypt" the meaning of the properties used in the code snippet above based on the following link (along many other tutorials and articles on the subject) to make sense in relation to WS-Trust and the certificates at hand.
http://cxf.apache.org/javadoc/latest/org/apache/cxf/ws/security/SecurityConstants.html
I have tried all sorts of combinations using the constants but with no success.
How do I "pass" the service certificate (webservice-encryption) to the STS to tell it "this is the service that I want to use"?
By the way I have captured the traffic with Fiddler, and the request looks perfectly right compared to traffic captured with the NetBeans solution i.e. it contains timestamp, encrypted sections etc.
I KEEP GETTING "The signature or decryption was invalid"
Can anyone help please?
What does the response method from the STS look like? Is it an error message or does it look like the call succeeded? If it is an error message then it looks like you may be using the wrong certificates...you will need to enable logging on the service to figure out what the exact error is. If the call succeeded, then enable DEBUG logging on the client side and see what the problem is.
Colm.
We had a similar problem. Perhaps you must add JCE Unlimited Strength Policy jar files to JDK?

URL fetch service - is https secure or not?

I'd like to use the URL fetch service for app engine (java). I'm just sending a POST to one of my own servers from a servlet.
AppEngine -> post-to: https://www.myotherserver.com/scripts/log.php
I'm reading the url fetch doc:
Secure Connections and HTTPS
An app can fetch a URL with the HTTPS method to connect to secure servers. Request and response data are transmitted over the network in encrypted form.
The proxy the URL Fetch service uses cannot authenticate the host it is contacting. Because there is no certificate trust chain, the proxy accepts all certificates, including self-signed certificates. The proxy server cannot detect "man in the middle" attacks between App Engine and the remote host when using HTTPS.
I don't understand - the first paragraph makesit sound like everything that goes from the servlet on app engine, to my php script is going to be secure if I use https. The second paragraph makes it sound like the opposite, that it won't actually be secure. Which is it?
Thanks
There are two things HTTPS does for you. One is to encrypt your data so that as it travels over the internet, through various routers and switches, no one can peek at it. The second thing HTTPS does is authenticate that you are actually talking to a certain server. This is the part App Engine can't do. If you were trying to connect to www.myotherserver.com, it is possible that some bad guy named bob could intercept your connection, and pretend to be www.myotherserver.com. Everything you sent to bob would be encrypted on it's way to bob, but bob himself would be able to get the unencrypted data.
In your case, it sounds like you control both the sending server and the destination server, so you could encrypt your data with a shared secret to protect against this possibility.
The UrlFetch through https has been fixed allowing certificate server validation.
validate_certificate
A value of True instructs the application to send a request to the
server only if the certificate is
valid and signed by a trusted CA, and
also includes a hostname that matches
the certificate. A value of False
instructs the application to perform
no certificate validation. A value of
None defaults to the underlying
implementation of URL Fetch. The
underlying implementation currently
defaults to False, but will default to
True in the near future.

Resources