Cloud Endpoints HTTP Cookies - google-app-engine

I am implementing Cloud Endpoints with a Python app that uses custom authentication (GAE Sessions) instead of Google Accounts. I need to authenticate the requests coming from the Javascript client, so I would like to have access to the cookie information.
Reading this other question leads me to believe that it is possible, but perhaps not documented. I'm not familiar with the Java side of App Engine, so I'm not quite sure how to translate that snippet into Python. Here is an example of one of my methods:
class EndpointsAPI(remote.Service):
#endpoints.method(Query_In, Donations_Out, path='get/donations',
http_method='GET', name='get.donations')
def get_donations(self, req):
#Authenticate request via cookie
where Query_In and Donations_Out are both ProtoRPC messages (messages.Message). The parameter req in the function is just an instance of Query_In and I didn't find any properties related to HTTP data, however I could be wrong.

First, I would encourage you to try to use OAuth 2.0 from your client as is done in the Tic Tac Toe sample.
Cookies are sent to the server in the Cookie Header and these values are typically set in the WSGI environment with the keys 'HTTP_...' where ... corresponds to the header name:
http = {key: value for key, value in os.environ.iteritems()
if key.lower().startswith('http')}
For cookies, os.getenv('HTTP_COOKIE') will give you the header value you seek. Unfortunately, this doesn't get passed along through Google's API Infrastructure by default.
UPDATE: This has been enabled for Python applications as of version 1.8.0. To send cookies through, specify the following:
from google.appengine.ext.endpoints import api_config
AUTH_CONFIG = api_config.ApiAuth(allow_cookie_auth=True)
#endpoints.api(name='myapi', version='v1', auth=AUTH_CONFIG, ...)
class MyApi(remote.service):
...
This is a (not necessarily comprehensive list) of headers that make it through:
HTTP_AUTHORIZATION
HTTP_REFERER
HTTP_X_APPENGINE_COUNTRY
HTTP_X_APPENGINE_CITYLATLONG
HTTP_ORIGIN
HTTP_ACCEPT_CHARSET
HTTP_ORIGINALMETHOD
HTTP_X_APPENGINE_REGION
HTTP_X_ORIGIN
HTTP_X_REFERER
HTTP_X_JAVASCRIPT_USER_AGENT
HTTP_METHOD
HTTP_HOST
HTTP_CONTENT_TYPE
HTTP_CONTENT_LENGTH
HTTP_X_APPENGINE_PEER
HTTP_ACCEPT
HTTP_USER_AGENT
HTTP_X_APPENGINE_CITY
HTTP_X_CLIENTDETAILS
HTTP_ACCEPT_LANGUAGE

For the Java people who land here. You need to add the following annotation in order to use cookies in endpoints:
#Api(auth = #ApiAuth(allowCookieAuth = AnnotationBoolean.TRUE))
source
(Without that it will work on the local dev server but not on the real GAE instance.)

Related

How to avoid CORS error for a React - GraphQL application

I am currently trying to use camunda platform and in this concept I am building a react application to make a call to a graphQL api and perform some actions. So far, I have used the api with postman and does the job I want to, The graphql mutation is the following:
mutation claimTask ($taskId: String!, $assignee: String) {
claimTask (taskId: $taskId, assignee: $assignee) {
id
name
taskDefinitionId
processName
creationTime
completionTime
assignee
variables {
id
name
value
previewValue
isValueTruncated
}
taskState
sortValues
isFirst
formKey
processDefinitionId
candidateGroups
}
}
And the endpoint is
http://{my_ip}:8082/graphql
which is set in a personal vm server. What I am trying to do now, is make the same request through the react app (apollo client). So far, I am getting a cors policy error:
Access to fetch at 'http://{my_ip}:8082/graphql' from origin 'http://localhost:3000' has been blocked by CORS policy
I understand that I have to configure somehow the uri that can be accepted by the server. My question is, since I am using an existing api should I do this from the express server (apollo server) configuration? Because so far every solution I found talks about implementing the api from the scratch, including defining the schemas.
I have concluded, that I should use the express server to create a kind of proxy so that the react app will hit the api through there but I cannot figure out how exactly is this implemented.
I know that this is a vague question, but any suggestion could be very useful.
Thank you!!
It is a best practice to not hit the GraphQL API directly, but to create your own facade, which exposes the functionality your front-end needs, possibly in a more use case specific way. This means connectivity only needs to be allowed server-to-server between the back-ends. It is more secure as you don't need to open the API to the public and it also solves the cross-domain challenge you have. Your facade will be exposed under your domain.
Here is a example NestJS client "Generating the Tasklist service":
https://docs.camunda.io/docs/apis-clients/tasklist-api/tasklist-api-tutorial/#generating-the-tasklist-service
On your express backend you would do something similar.
(This example uses a Java back-end with react, but I am guess you want JS: https://github.com/camunda-community-hub/camunda-8-lowcode-ui-template/blob/main/src/main/java/org/example/camunda/process/solution/facade/TaskController.java .)

Does kiwi tcms has Node.js api?

I practice to use tcms_api in python now, but i want to use node.js to call kiwi api.
I did not find the relevant information on the network.
Can anyone give me some suggestions??
Thanks.
The API is exported both over XML-RPC and JSON-RPC protocols. The JSON-RPC protocol is very simple, see https://www.jsonrpc.org/specification and you can easily create your own client.
While Kiwi TCMS doesn't provide a stand-alone JavaScript client you can use the following as an example:
https://github.com/kiwitcms/Kiwi/blob/master/tcms/static/js/jsonrpc.js
Warning: the code above doesn't handle authentication b/c it is designed to execute in the browser which already keeps a session cookie after the user has been logged in. If you are designing a generic client that will be used outside the browser your first call should be to the Auth.login method which returns the session ID and also sets a Cookie header in the response. The existing Python API client just parses the Cookie header and provides it on subsequent requests, see:
https://github.com/kiwitcms/tcms-api/blob/master/tcms_api/xmlrpc.py#L19

How to protect my api call from CSRF attack

I am working on angular js app,and tried to make a simple login page and tried to request my server API for authenticate my login call.Here what and how i planned to do.
Note: I am assuming that server is responsible for validating my token and request.
Provide username password to server via API call.
On getting authenticated the server will generate a token for my App(through which i made a call).
I stored this in my browser's COOKIE.
This Cookie (auth token) will be further used by app to to make each and every HTTP call to API.
Now this approach is working fine for me,but I believe it is openly available for CSRF attack.
In order to avoid the CSRF attack from my browser,i provide APP id or (version id) to my code which also travel with cookie to the API for http call.
The idea behind using this version id or App id,is this can be treated as a signature of my code,ie request is coming from the signed (verified) app who has alloted token=cookie value.
i just want to know how better my approach is and how much secure it is for my basic app point of view and for my major (wide project) app.
Here i am trying to show via a rough diagram
apologies for this tiny view and bad handwriting of the diagram.
Backend frameworks like Laravel have this pretty built in: csrf-protection.
You can pass the token to Angular by using angular's constant function: $provide#constant.
So after you initialize your app you could say: angular.module('myApp').constant('<?php echo csrf_token(); ?>'); and Laravel would do the rest. If you would want to implement a technique like this yourself, you should look into Laravel's source code: https://github.com/laravel/framework/blob/a1dc78820d2dbf207dbdf0f7075f17f7021c4ee8/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php.
Adding App ID + Version ID to each request won't protect your system from a CSRF attack, unless these are in a custom header - and if they are you might as well just use X-Requested-With because any non standard header is protected going cross domain, provided you haven't enabled CORS with an open policy.
The reason that checking App ID + Version if set in the query string or POST data is that the attacker can readily gain this information to add the App ID + Version ID to their cross site requests. Another method that would work for you is the Double Submit Cookies technique. Generate a random 128 bit string using a CSPRNG and then set this as a cookie value (e.g. CSRFCookie). On each request to your API, also pass this value. e.g. in the query string: CSRFCookie=<generated value>. On the server side you simply check that the values match. An attacker does not know the cookie value, therefore they cannot add the same value to the query string.
This method does have some minor vulnerabilities, only really exploitable in a MITM scenario or if you do not control all subdomains. Short answer: Use HTTPS only for all your subdomains and implement HSTS.

Is a single Cookie Based API for multiple frontends possible from a CORS perspective?

I originally wrote an REST API to work with a previously written mobile app. The mobile programmer requested from me to generate an auth_token on login that he will pass as a header on each request that needed authentication. This API runs at api.example.com.
Later on, I was commissioned to write an AngularJS app that communicates with this API, so I had to use Access-Control-Allow headers on the backend for OPTIONS requests to be CORS compatible CORS so my browser allows the connection (looks like iOS does not look for this headers). This app runs at one.example.com.
Now, I have to write a second AngularJS app that will run at two.example.com and there's a third being planned for the near future at three.example.com.
My problem is that my Access-Control-Allow-Origin header looks like this:
Access-Control-Allow-Origin: http://one.example.com:80
* is not allowed, nor I'm able to set this header to more than one origin. So as far as I can see I have two solutions:
Implement token-based authentication in parallel to the current cookie-based one. I'm thinking on this. This will of course take some time I'm willing to save.
Send the requester a header or param to the API endpoint identifying the app on the OPTIONS request and server-side, produce the CORS headers accordingly. I don't even know if it's possible and this looks nasty for even thinking it.
Any better ideas?
If they have the same origin, example the same domain (example.com) or the same subdomain (1.ex.example.com and 2.ex.example.com) they can share the same cookie. Because cookie is based on the domain itself.

Custom SignIn & SignUp on RESTlet + GAE/J?

I am currently working on a small project using RESTlet on Google App Engine/Java.
I was searching.. searching.. and couldn't find the exact or understandable solutions for my doubts.
My question is that How am I suppose to implement my own SignIn & SignUp module without using google's UserService or Spring Security??
Is there any actual sample code available??
I mean SignUp part is just a simple JDO insert & select module. let's just say I've done it.
How am I supposed to handle each user's request session and authentication??
I am thinking about using HTTPS on every request.
Any suggestions or help would be really appreciated!
Thanks in advance.
In Restlet, you have security support on both client and server sides. On client side, you can specify security hints using the ChallengeResponse entity. This feature is open and you can specify the authentication type you want. In the following code, I use an http basic authentication based on username / password:
ClientResource cr = new ClientResource(uri);
ChallengeScheme scheme = ChallengeScheme.HTTP_BASIC;
ChallengeResponse authentication = new ChallengeResponse(
scheme, "username", "password");
cr.setChallengeResponse(authentication);
Restlet will automatically build necessary headers in the corresponding request. You can note that Restlet supports a wide range of authentication types through its extensions. I know that some work is done at the moment to support OAuth v2 (see http://wiki.restlet.org/developers/172-restlet/257-restlet/310-restlet.html).
On the server side, you need to secure accesses at routing level using the ChallengeAuthenticator entity, as described below. This can be done within your Restlet application:
public Restlet createInboundRoot() {
Router router = new Router(getContext());
ChallengeAuthenticator guard = new ChallengeAuthenticator(getContext(),
ChallengeScheme.HTTP_BASIC, "realm");
guard.setVerifier(verifier);
guard.setEnroler(enroler);
guard.setNext(router);
return guard;
}
Like for client side, this support is generic and is based on two interfaces that need to be specified on the guard:
The verifier one to check if authentication is successful
The enroler one to fill roles for the authenticated user
You can notice that same security technologies need to be use on both sides...
If you want to manage authentication session for user, you need to implement it by yourself using cookies.
When authentication successes on server side, you can return a cookie containing a security token that allows you checking the user from your database (for example). Some code like below can implement that:
CookieSetting cookie = new CookieSetting(0,
SECURITY_COOKIE_NAME, securityToken);
Series<CookieSetting> cookieSettings = response.getCookieSettings();
cookieSettings.clear();
cookieSettings.add(cookie);
You can extend for example the SecretVerifier class of Restlet to add a test on security data received and add this code when receiving the security cookie.
On client side, you need to add hints for authentication the first time and then re send the security cookie following times, as described below:
ClientResource clientResource = (...)
(...)
Cookie securityCookie = new Cookie(0,
SECURITY_COOKIE_NAME, securityToken);
clientResource.getRequest().getCookies().clear();
clientResource.getRequest().getCookies().add(securityCookie);
Hope it will help you!
Thierry
If you are interested in re-using social accounts, you need to integrate with each one like facebook oauth
And/Or use the app engine authentication via OpenID
Both ways define an API to authenticate a client, you can use the UserService or manage your own state via cookies.

Resources