i have created a Zuul proxy that routes request to a secured endpoint in a microservice (basic auth).
My Zuul proxy runs on port 8888.
My Secured Microservice has an endpoint /api/foo with a username:password authentication via Spring Security. With a service id equal to secure-service.
Now whenever i access http://localhost:8888/secure-service/api/foo, the browser prompt me to enter my username and password (proof that it really routes to secure-service). But then after entering, it just keeps on asking my credentials.
i also tried accessing it via curl,
curl http://username:password#localhost:8888/secure-service/api/foo and i get 401 response.
Why is that happening?
Then i tried removing spring security dependencies and configuration on my secured-service and everything works fine. But i really want to have basic authentication.
Thank you for reading.
i finally found the answer :)
There's a configuration Property in Zuul called
zuul.sensitive-headers
This property is a collection of strings that contains headers that will not be included to pass to microservices. And currently, Spring Cloud Zuul (ver 2.2.1.RELEASE) by default sets these 3 values.
Cookie,Set-Cookie,Authorization
For the love of God, they put Authorization as one of sensitive headers that's why you will keep getting 401 unauthorized response whenever Zuul tries to route to a secured microservice.
The solution is just to remove Authorization in Config Property in your Zuul Application.
zuul.sensitive-headers=Cookie,Set-Cookie
Hope it helps.
Related
I can’t seem to figure out how to use two different IDPS and 2 different applications URLs. I had this working on weblogic but not with a spring boot application using the spring saml security.
One important part is that we have two different URLs.
Proxy URL for external users. They must use this URL as they are not in the network.
a. These users hit IDP-A
Internal URL for internal users.
b. These users hit IDP-B
The metadata we sent to the each of the IDPs use the same entity ID but different endpoint URLs.
One thing we did was turn on discovery and where able to hit each IDP but it always redirects us to the internal URL. I noticed that AssertionConsumerServiceUrl is always set to the internal URL, which explains why it is returned to is the same. In our weblogic implementation we do not send AssertionConsumerServiceUrl.
Can we exclude AssertionConsumerServiceUrl?
Do you know if the configuration I am attempting to do is even possible?
you can autowire the MetadataManager bean in your service and then call the addMetadataProvider to inititate a metadata.
You can get the entityId from the Metadata Obtained from IDP and can append to the url :
'http:///saml/login?idp=' by hitting this url it will redirect you to appropriate IDP login.
I'm using Oracle Application Express 11g.
To secure RESTful services I want to create Third Party Authentication for it.
According to this article : http://www.oracle.com/technetwork/developer-tools/rest-data-services/documentation/listener-dev-guide-1979546.html
In order to register my third party user I need to access this url : https://server:port/ords/resteasy/ui/oauth2/clients/ as I don't have SSL every time I face this error(entring the url in http) :
403-Forbidden
This resource must be accessed over HTTPS only
The Question is : how can I disable "security verify SSL" in apex, in order that I never face this error again.
Note that there is no error like this in other pages because I'm not forced to use https, and I'm receiving this error entring the url in http.
https://docs.oracle.com/cd/E37099_01/doc.20/e25066/install.htm#AELIG7183
1.4.5 Using OAuth2 in Non HTTPS Environments
RESTful Services can be protected with the OAuth2 protocol to control access to nonpublic data. To prevent data snooping, OAuth2 requires all requests involved in the OAuth2 authentication process to be transported using HTTPS. The default behavior of Oracle REST Data Services is to verify that all OAuth2 related requests have been received using HTTPS. It will refuse to service any such requests received over HTTP, returning an HTTP status code of 403 Forbidden.
This default behavior can be disabled in environments where HTTPS is not available as follows:
Locate the folder where the Oracle REST Data Services configuration is stored.
Edit the file named defaults.xml.
Add the following setting to the end of this file just before the </properties> tag.
<entry key="security.verifySSL">false</entry>
Save the file.
Restart Oracle REST Data Services if it is running.
Note that it is only appropriate to use this setting in development or test environments. It is never appropriate to use this setting in production environments because it will result in user credentials being passed in clear text.
I am struggling to access the Dynamics 2016 CRM OData Web APIs from a console application.
We have Dynamics CRM 2016 installed, configured with Claims-based authentication, and using AD FS v3.0.
My understanding is that a console app (or web app) should be able to access the Web APIs using Windows integrated authentication (i.e. NTML or Kerberos) without any special treatment ... or maybe the OAuth flow should work when enabled.
For a regular user accessing Dynamics "pages", the authentication works fine (redirection to AD FS log in page), but accessing the OData APIs does not seem to work (for instance : https://crm.domain.org/api/discovery/v8.0/ ) :
in a browser I get a Windows login prompt and typing valid credentials always results in a HTTP 401 unauthorized error
in a brower, if I navigate to a Web API url after having logged on on the pages , then I can access the Web APIs (i.e. some cookies must be set and I am already implicitly authorized)
from code, using an HttpClient with specific valid credentials (or current credentials) , I also get a 401
Things I have tried :
if I disable Claims-based authentication completely , HttpClient works fine and I can access the OData APIs
if I leave Claims-based authentication enabled, and activate OAuth via PowerShell Add-PSSnapin Microsoft.Crm.PowerShell ; $ClaimsSettings = Get-CrmSetting -SettingType OAuthClaimsSettings; $ClaimsSettings.Enabled = $true ; Set-CrmSetting -Setting $ClaimsSettings ;.
Windows integrated authentication still does not work, but using Bearer authentication is now possible. I can use this snippet to retrieve the OAuth Endpoint for token generation, and use AuthenticationContext.AcquireTokenAsync to issue a token, and then pass it in the Authorization HTTP Header ... but then, no matter what, I get this error :
Bearer error=invalid_token, error_description
=Error during token validation!, authorization_uri=https://our.adfs.domain.org/adfs/oauth2/authorize, resource_id=https://crm.domain.org/
Am I missing something ? is that possibly a configuration issue ?
From this answer from the dynamics community forum, it looks like the api is pretty strict about the parameters and headers it requires. When doing the request, make sure you have the Cache-Control: no-cache and Content-Type: application/x-www-form-urlencoded headers set.
In the subsequent request to access the api with the retrieved token you should set the Authorization header in the form of Bearer: TOKEN (worth noting since a lot of people actually thought they could directly put the token), the OData-Version: 4.0, Cache-Control: no-cache and Accept: application/json ones too.
Looking at the different OAuth endpoints and the previously linked answer, I'm not sure the authorization uri is the right one (eg https://login.windows.net), so do you make sure that's correct. It's also stated that you should use the OAuth endpoint url and use the WWW-Authenticate header that returns the valid one, even if this route will respond with a 401. I'm sure you already saw this example, but it provides a pretty complete overview of an auth flow and how the token is retrieved using AcquireTokenAsync where you pass your resource and clientID. I might also be looking at an updated page and it's not relevant in your case.
You also want to check if the resource id you specified is the correct one, some people reported to have to specify one in the form of https://crm3.domain.org/ or https://crm4.domain.org/ instead of the bare one, so that could be one thing.
It could also be a configuration issue, given what #l said about the fact an IP would work instead of the domain name. It could very well be a certificate problem, where it's not validated correctly or untrusted, thus creating the error you see even if it's not the appropriate message. Also make sure your 443 port is allowed through your firewall(s).
One interesting post where the author explains that the Form Authentication setting of the AD FS Management Console was required for him to proceed (it's CRM 2013, but might still be related).
I have two spring-boot processes. I have Spring Security enabled on both, and I'm using Spring Security OAuth2 SSO setup. I'm also using Eureka and Zuul to allows calls into Boot1 to call into services in Boot2. UI is using Angular with REST calls into the services, and the token being used is a Json Web Token.
This all seems to work, certainly in the UI. All the requests use the Authorization header (which contains the JWT) and the spring security filter in the services successfully parse the JWT and extracts the Security Context from it. As part of the Spring Web processing, it adds a JSESSIONID value to the client's cookie.
Recently, I only had Spring security on Boot1. When calling rest services into Boot1, which end up using Zuul to forward requests to Boot2, all I required in the rest client was to include the Authorization header with the JWT and it all worked fine.
However, I have recently added Spring Security to Boot2 (using the #EnableResourceServer annotation) and now rest calls fail unless I have both the Authorization header as well as a Cookie header that contains a JSESSIONID value. Calls don't fail, but they return empty values.
I've enabled logging to Spring Security, and it validates all correctly in Boot1. It's going into the same ZuulFilter. But there's no activity on Boot2.
Is there something in Zuul that requires a JSESSIONID value to be defined in order for it forward the request? Or is this in Boot2, where it is expecting a JSESSIONID header value due to the introduction of Spring Security filters?
--- update ---
I've stepped through boot1. From what I can see, code in the OAuth2TokenRelayFilter is throwing an exception. Specifically, the method getAccessToken is calling restTemplate.getAccessToken().getValue (line 90, version 1.1.0-RELEASE) which throws a UserRedirectRequiredException.
So, while the TokenRelayFilter has a token, it's attempting to refresh it. When it receives an exception, it's throwing a BadCredentialsException instead of using what's already been defined.
--- update 2 ---
Putting a breakpoint in OAuth2RestOperationsConfiguration, making rest calls without the JSESSIONID always ends up with a new DefaultOAuth2ClientContext to be created, as it's trying to create session-scoped beans. With the JSESSIONID, it's using a persisted DefaultOAuth2ClientContext, which will have the context.
So, is it possible to, when constructing the DefaultOAuth2ClientContext, to see if the request contains the token and uses it? Or something like this? We're trying to move to stateless services, and this seems to be a hurdle towards this.
This turned out to be an issue with the client-id values used by the different parts of the system.
Looking at OAuth2TokenRelayFilter, it is attempting to refresh the token if the client-id defined for the resource server (boot1) matches that which is defined as part of the token contained within the token provided with the request. In my case, this was true: the token was defined using the same client-id.
That really is not correct. When I update my rest client to use a token, but using a different client-id when requesting the token, then the request is forwarded correctly as expected, without the need for a jsessionid. This is exactly what I want.
I suspect that this was caused, in the end, by incorrect use of client-id values by the components of my system.
We are currently using AWS ELB -> Apache in front of our Tomcat instance running Grails. We use Apache to redirect http requests to https requests. This works fine for us on our regular site. The issue arrives when trying to embed our site within an iframe on Chrome. Chrome does not like an https site redirecting to an http page (even if that page subsequently redirects to https). The reason this happens is that to Spring Security it looks like we're on http because we're behind a load balancer. Here is the network ping pong from Developer Tools:
Here is the problem when putting that same page within an iframe on Chrome.
We have found many solutions that will allow the Spring Security Grails plugin to redirect http requests to https request for certain URL patterns. Here and here are two of these examples. We have already solved this issue by having Apache intercepting http requests and redirecting to https.
The issue is that Chrome won't even make the http request within the iframe. We need an ability to tell Spring Security that even though the saved request you receive is using http, we need you to change that to https once you complete the authentication.
One solution we thought may work was changing to a relative URL using contextRelative instead of the absolute URL, which Spring Security views as http because of the ELB proxy. This post seemed to suggest the same, but the solution also did not change the URL generated when changing contextRelative to "true".
How can we tell the Grails Spring Security plugin to always either format the URLs as relative or force them to an https scheme so that we can run the application within an iframe in Chrome?
If you want to modify the SavedRequest then you can implement your own SavedRequestAwareAuthenticationSuccessHandler that will override the protocol when it pulls the saved request out of the cache and force it to be https.