How to secure google cron service tasks on GAE flexible env? - java

I want from an url:
To be called only by the google cron service
Not to be called by a user in a web browser
Whats on the google docs didn't work: when the cron service calls the servlet, it also give me a 403 error - forbidden access...
And there is no security related informations regarding the app.yaml file for the flexible env.
Two observation I have made:
Google states that "Google App Engine issues Cron requests from the IP address 0.1.0.1". But I got another IP address launching the cron job:
From this IP address, the HTTP header actually contains the X-Appengine-Cron (with the value true)
Do you have any ideas ?

The referenced doc snippet mentioning the securing method based on login: admin config in the handlers section of the app.yaml file is incorrect - the handlers section is applicable to the (non-java) standard environment app.yaml, not the flexible environment one. So you might want to remove such undocumented config, just to be sure it doesn't have some unexpected/undesired negative effect.
Checking just the X-Appengine-Cron should be sufficient enough: it can only be set by the cron service of your app. From Securing URLs for cron:
Requests from the Cron Service will also contain a HTTP header:
X-Appengine-Cron: true
The X-Appengine-Cron header is set internally by Google App Engine. If
your request handler finds this header it can trust that the request
is a cron request. If the header is present in an external user
request to your app, it is stripped, except for requests from logged
in administrators of the application, who are allowed to set the
header for testing purposes.
As for why exactly the response to the cron request is 403 - you should show your handler code which is (most likely) the one responsible for building the reply.

Related

Spring boot oauth2 response with redirect url as underlying service instead of proxy (Gateway)

I am implementing oauth2 server using Springboot
I have four microservices
Sales (sales)
Inventory (inventory)
IAM service (Authorization Server, with Oauth2) (http://iam:8089)
Gateway (gateway on http://www.gateway.com)
All these services are behind the Spring clould gateway, and its deployed under K8S, And Gateway is exposed as external interface.
Now if I try to do authenticat user using oauth2 throught gateway like below.
Step 1 :
Http Request http://www.gateway.com/oauth/authorize
So in Response header I am getting like
Location: http://iam:8089/v1/oauth/login (But expectation is http://www.gateway.com/oauth/login)
and because of that browser
redirect me to http://iam:8089/oauth/login
Where Ideally I am expecting that also routed through gateway service something like
http://www.gateway.com/oauth/login
Can someone please help me to solve this.
Thanks
Alpesh
Sounds like a good setup in line with what we recommend at Curity in our IAM Primer Article, with the Authorization Server (AS) behind a reverse proxy or gateway.
In your case the AS listens at http://Iam:8089 but that is an internal URL. The AS also has a 'Base URL' that is used by internet clients, and this is the URL of the gateway, which is http://www.gateway.com in your example:
It will be returned to clients in OpenID Connect discovery requests
It will be returned to browsers in browser redirects during authentication
There should be somewhere in Spring OAuth2 Server where you set the Base URL, similar to that in the Curity Identity Server (see image below). The process should be to set this value and then verify that it is returned in a metadata request. You should then be configured correctly.
In Spring I expect the setting you need is in the fluent configuration somewhere - maybe one of the Configurer classes. I find it pretty hard to find what I'm looking for in Spring though.

How to find the referrer when a web service is called directly by java code in a batch job?

We are using a secured Rest Service which generates a token based on a user name, password and referrer. It works fine when we run it from a Web project because it is clear the referrer is just the url of the web project. We need to run the code in a batch job and we are getting an invalid token error and we suspect the issue is with the referrer value. Since there is no url involved in running the batch job what should we use for the referrer value?
The code which calls the Rest Service is generated by the Rest Service WSDL and is located in an EJB module. The code is triggered by a Quartz timer.
EDIT:
I don't have control over how the request is sent. All I can do is use the method provided by the java client created from the service wsdl. I also have no control over how the token is created. The code which generates the token requires I pass it the referrer and it is used to generate the token. When the code is run in an app, then using the url of the app as the referrer works, the token is accepted. When the batch job runs there is no url, there is no browser involve, it is just code running on a server which executes the java method.
Doing some more research I found the code which generates the token will also accept the IP address which is what I think I have to do to use it in a batch job.

Spring boot Hadoop, Webhdfs and Apache Knox

I have a Spring boot application which is accessing HDFS through Webhdfs secured via Apache Knox secured by Kerberos. I created my own KnoxWebHdfsFileSystem with custom scheme (swebhdfsknox) as a subclass of WebHdfsFilesystem which only changes the URLs to contain the Knox proxy prefix. So it effectively remaps requests from form:
http://host:port/webhdfs/v1/...
to the Knox one:
http://host:port/gateway/default/webhdfs/v1/...
I do this by overriding two methods:
public URI getUri()
URL toUrl(Op op, Path fspath, Param<?, ?>... parameters)
So far so good. I let spring boot create FsShell for me and use it for various operations such as list files, mkdir etc. All work fine. Except copyFromLocal which as documented requires 2 steps and redirect. And on the last step when the filesystem tries to PUT to the final URL which received in Location header it fails with error:
org.apache.hadoop.security.AccessControlException: Authentication required
at org.apache.hadoop.hdfs.web.WebHdfsFileSystem.validateResponse(WebHdfsFileSystem.java:334) ~[hadoop-hdfs-2.6.0.jar:na]
at org.apache.hadoop.hdfs.web.WebHdfsFileSystem.access$200(WebHdfsFileSystem.java:91) ~[hadoop-hdfs-2.6.0.jar:na]
at org.apache.hadoop.hdfs.web.WebHdfsFileSystem$FsPathOutputStreamRunner$1.close(WebHdfsFileSystem.java:787) ~[hadoop-hdfs-2.6.0.jar:na]
at org.apache.hadoop.io.IOUtils.copyBytes(IOUtils.java:54) ~[hadoop-common-2.6.0.jar:na]
at org.apache.hadoop.io.IOUtils.copyBytes(IOUtils.java:112) ~[hadoop-common-2.6.0.jar:na]
at org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:366) ~[hadoop-common-2.6.0.jar:na]
at org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:338) ~[hadoop-common-2.6.0.jar:na]
at org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:302) ~[hadoop-common-2.6.0.jar:na]
at org.apache.hadoop.fs.FileSystem.copyFromLocalFile(FileSystem.java:1889) ~[hadoop-common-2.6.0.jar:na]
at org.springframework.data.hadoop.fs.FsShell.copyFromLocal(FsShell.java:265) ~[spring-data-hadoop-core-2.2.0.RELEASE.jar:2.2.0.RELEASE]
at org.springframework.data.hadoop.fs.FsShell.copyFromLocal(FsShell.java:254) ~[spring-data-hadoop-core-2.2.0.RELEASE.jar:2.2.0.RELEASE]
I suspect the problem is the redirect somehow but can't figure out what might be the problem here. If I do the same requests via curl the file is successfully uploaded to HDFS.
This is a known issue with using existing Hadoop clients against Apache Knox using the HadoopAuth provider for kerberos on Knox. If you were to use curl or some other REST client it would likely work for you. The existing Hadoop java client doesn't expect a SPNEGO challenge from the DataNode - which is what the PUT in the send step is talking to. The DataNode expects the block access token/delegation token issued by the NameNode in the first step to be present. The Knox gateway however will require SPNEGO authentication for every request to that topology.
This is an issue that is on the roadmap to be addressed and will likely become hotter with interest moving more inside the cluster rather than only accessing resources through it from the outside.
The following JIRA tracks this item and as you can see from the title is related to DistCp which is a similar usecase:
https://issues.apache.org/jira/browse/KNOX-482
Feel free to take a look and lend a hand with testing or developing - it would all be most welcome!
Another possibility would be to change the Hadoop java client to deal with a SPNEGO challenge for the DataNode as well.

Finding the Requested Server Host Ip?

I have an application(client application) hosted in a Tomcat server and this application has to be integrated as a Tab in another application(parent application). In the Parent application the user authentication is done. in the Parent application Html we are using iframe to integrate the client. Everything is working fine except this. The Problem is, if some one knows the URL they can access the client application. How can we avoid this.? we are using JAVA,SERVLET,HTML,Tomacat as technologies.
Thanks :)
One of possible solution is token based authentication.
The parent application should add special token either as a URL parameter or as HTTP header. The token should contain authentication information in encrypted form. "Client" application should extract the information and decide whether authentication passed or failed. In order to guarantee that no-one can copy this token and then get unauthenticated access to your application you should make the token to be one-time or limited in time range.
You can also use x-frame-options in your header. I found this article with some quick googling: http://www.jtmelton.com/tag/x-frame-options/
This will prevent your app from loading in frames except for the domains which you allow permission. You might check into browser compatibility, I'm not sure when this was implemented in different browsers.
Also, you can check the 'host' and 'referrer' header fields to check that requests are coming from a domain you trust before sending a response.
OAuth is the standard for authorizing third party apps. You should check into that as an authentication approach.
None of these will give you a completely secure app. You should consider consulting with a security expert.
From parent application add cookie and from child application get that cookie and validate user.(if both are running on same domain).

createLoginURL creates invalid request URL in GAE

I get the following error from following piece of code. I am trying to login to Google sites service through GAE apps.
"The page you requested is invalid. "
String authenticationUrl = userService.isUserLoggedIn()
? userService.createLogoutURL(MainServlet.MAIN_URL)
: userService.createLoginURL(MainServlet.MAIN_URL+"?close=1");
googleData.setAuthenticationUrl(authenticationUrl);
The complete url for login
https://www.google.com/a/example.com/ServiceLogin?service=ah&passive=true&continue=http://myapp.appspot.com/_ah/login?continue=http://myapp.appspot.com/main%3Fclose%3D1&ltmpl=ga&ahname=Myapp+Google+Sites&sig=7cbc9f7c9e6ca443ed49f7ce9465e775
I think that you may have misunderstood the use and purpose of createLoginURL. This method is intended to provide a URL that allows someone to log in to your application and your application alone. It does not provide a means to log in to other Google services such as Sites.
It is possible to have your application log on to and access Sites or any other secured web application, but Google AppEngine does not provide a canned means of doing so. You will need to write the code to do it yourself.
Generally, what will happen is that you will request a URL and the response will have an HTTP status code of 302 with the URL of the login page located in the Location header field. You would then send a request to that page which should come back with a 200 response and somewhere inside the body of the response would be a username and password field that you would need to provide and POST back. If the credentials were valid, the server might then return an authentication cookie which you would pass on each subsequent request.
If you are versed at all in Python, you can see an example of how this works in some code from my AppEngine MVC framework project. Look at this file:
http://code.google.com/p/gae-mvc-engine/source/browse/trunk/MVCTests.py and check out the ActiontestCase.run_action method. It handles making a request to an AppEngine application that requires authentication. It is not yet terribly-well commented -- and for that I aplogize -- but I hope that it will provide a useful example. If, indeed, I have understood the nature of your problem correctly.

Categories