Skip to content

Commit

Permalink
appengine/oauth2 sample (#168)
Browse files Browse the repository at this point in the history
* appengine/oauth2 sample
* Also add minor formatting change to url fetch.
* check style helping too much.
  • Loading branch information
lesv committed Apr 20, 2016
1 parent c6749dd commit bd070d9
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ dependency-reduced-pom.xml
buildNumber.properties

service-account.json

# intellij
.idea/
*.iml
7 changes: 7 additions & 0 deletions appengine/oauth2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Eclipse files
.project
.classpath
.settings

# Target folders
target/
41 changes: 41 additions & 0 deletions appengine/oauth2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Google App Engine Standard Environment
## Oauth2 Sample

This sample demonstrates using the Oauth2 apis to create an authenticaion filter.

See the [Google App Engine standard environment documentation][ae-docs] for more
detailed instructions.


## Setup
1. In the [Cloud Developers Console](https://cloud.google.com/console) > API Manager > Credentials,
create a Oauth Client ID for a Web Application. You will need to provide an authroized JavaScript
origin. Typically, https://projectID.appspot.com.
1. Edit `src/main/webapp/index.html` and change `YOUR_CLIENT_ID_HERE.apps.googleusercontent.com` to
Client ID from the prior step.

## Running locally
NOTE: The app can be run locally, but the Oauth2 APIs do not work with the development server.

$ mvn appengine:devserver

## Deploying
$ mvn appengine:update -Dappengine.appId=YOUR-PROJECT-ID -Dappengine.version=SOME-VERSION

1. Using your browser, visit `https://YOUR-PROJECT-ID.appspot.com`, click Sign In.

1. The Sign In process will then request some text from your app, and then display it, if
the id matches the list in `src/main/java/com/example/appengine/Oauth2Filter.java`.

## Adding you to the list of valid users
NOTE: Typically, you would use this for Service Accounts, but user accounts work as well.

1. Enable logging by uncommenting the context.log line in
`src/main/java/com/example/appengine/Oauth2Filter.java`, redeploy, and visit the page
1. Look at the logs in [Cloud Developers Console](https://cloud.google.com/console) > Logs.

1. Add the `tokenAudience` to the `allowedClients`.

1. Deploy and visit the page again.

[ae-docs]: https://cloud.google.com/appengine/docs/java/
60 changes: 60 additions & 0 deletions appengine/oauth2/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!--
Copyright 2015 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project>
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<groupId>com.example.appengine</groupId>
<artifactId>appengine-oauth2</artifactId>

<properties>
<appengine.sdk.version>1.9.34</appengine.sdk.version>
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.source>1.7</maven.compiler.source>
</properties>
<parent>
<groupId>com.google.cloud</groupId>
<artifactId>doc-samples</artifactId>
<version>1.0.0</version>
<relativePath>../..</relativePath>
</parent>

<dependencies>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-1.0-sdk</artifactId>
<version>${appengine.sdk.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<type>jar</type>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<!-- for hot reload of the web application -->
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
<plugins>
<plugin>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>${appengine.sdk.version}</version>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.appengine;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// [START example]
@SuppressWarnings("serial")
public class HelloServlet extends HttpServlet {

@Override
public void doPost(final HttpServletRequest req, final HttpServletResponse resp)
throws IOException {
PrintWriter out = resp.getWriter();
out.print("Hello, world"); // simple hello world response
}
}
// [END example]
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.appengine;

import static com.google.appengine.api.utils.SystemProperty.environment;

import com.google.appengine.api.oauth.OAuthRequestException;
import com.google.appengine.api.oauth.OAuthService;
import com.google.appengine.api.oauth.OAuthServiceFactory;
import com.google.appengine.api.oauth.OAuthServiceFailureException;
import com.google.appengine.api.users.User;
import com.google.appengine.api.utils.SystemProperty;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

/**
* Filter to verify that request has a "Authorization: Bearer xxxx" header,
* and check if xxxx is authorized to use this app.
*
* Note - this is to demonstrate the OAuth2 APIs, as it is possible to lockdown some
* of your app's URL's using cloud console by adding service accounts to the project.
*/
public class Oauth2Filter implements Filter {

private ServletContext context;

@Override
public void init(final FilterConfig config) throws ServletException {
this.context = config.getServletContext();
}

// [START oauth2]
@Override
public void doFilter(final ServletRequest servletReq, final ServletResponse servletResp,
final FilterChain chain) throws IOException, ServletException {
final String scope = "https://www.googleapis.com/auth/userinfo.email";
Set<String> allowedClients = new HashSet<>();

HttpServletResponse resp = (HttpServletResponse) servletResp;

OAuthService oauth = OAuthServiceFactory.getOAuthService();

allowedClients.add("407408718192.apps.googleusercontent.com"); // list of client ids to allow
allowedClients.add("755878275993-j4k7emq6rlupctce1c28enpcrr50vfo1.apps.googleusercontent.com");

// Only check Oauth2 when in production, skip if run in development.
SystemProperty.Environment.Value env = environment.value();
if (env == SystemProperty.Environment.Value.Production) { // APIs only work in Production
try {
User user = oauth.getCurrentUser(scope);
String tokenAudience = oauth.getClientId(scope);

// The line below is commented out for privacy.
// context.log("tokenAudience: " + tokenAudience); // Account we match

if (!allowedClients.contains(tokenAudience)) {
throw new OAuthRequestException("audience of token '" + tokenAudience
+ "' is not in allowed list " + allowedClients);
}
} catch (OAuthRequestException ex) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND); // Not allowed
return;
} catch (OAuthServiceFailureException ex) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND); // some failure - reject
context.log("oauth2 failure", ex);
return;
}
}
chain.doFilter(servletReq, servletResp); // continue processing
}
// [END oauth2]

@Override
public void destroy() { }

}
20 changes: 20 additions & 0 deletions appengine/oauth2/src/main/webapp/WEB-INF/appengine-web.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- [START_EXCLUDE] -->
<!--
Copyright 2016 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- [END_EXCLUDE] -->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>YOUR-PROJECT-ID</application>
<version>YOUR-VERSION-ID</version>
<threadsafe>true</threadsafe>
</appengine-web-app>
27 changes: 27 additions & 0 deletions appengine/oauth2/src/main/webapp/WEB-INF/web.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<filter>
<filter-name>Oauth2Filter</filter-name>
<filter-class>com.example.appengine.Oauth2Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>Oauth2Filter</filter-name>
<url-pattern>/hello</url-pattern>
</filter-mapping>

<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.example.appengine.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
36 changes: 36 additions & 0 deletions appengine/oauth2/src/main/webapp/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="google-signin-scope" content="profile">
<meta name="google-signin-client_id" content="YOUR_CLIENT_ID_HERE.apps.googleusercontent.com" />

<script src="https://apis.google.com/js/platform.js" async defer></script>
<script>
function onSignIn(googleUser) {
// Useful data for your client-side scripts:
var access_token = googleUser.getAuthResponse().access_token;


var xhr = new XMLHttpRequest();
xhr.open('POST', '/hello');
xhr.setRequestHeader("Authorization", "Bearer "+access_token);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
document.getElementById('response').innerHTML = xhr.responseText;
document.getElementById('me').style = "display:inline;";
};
xhr.onError = function() {
document.getElementById('response').innerHTML = "Error";
document.getElementById('me').style = "display:inline;";
};
xhr.send();
}
</script>
</head>
<body>
<div class="g-signin2" data-onsuccess="onSignIn" data-theme="dark"></div>
<div id="me" style="display: none;">
<h1><span id="response"></span></h1>
</div>
</body>
</html>
3 changes: 3 additions & 0 deletions appengine/urlfetch/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ Copyright 2015 Google Inc. All Rights Reserved.
<version>1.0-SNAPSHOT</version>
<groupId>com.example.appengine</groupId>
<artifactId>appengine-URLFetch</artifactId>

<parent>
<groupId>com.google.cloud</groupId>
<artifactId>doc-samples</artifactId>
<version>1.0.0</version>
<relativePath>../..</relativePath>
</parent>

<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
Expand All @@ -38,6 +40,7 @@ Copyright 2015 Google Inc. All Rights Reserved.
<version>20160212</version>
</dependency>
</dependencies>

<build>
<!-- for hot reload of the web application -->
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<module>appengine/mailgun</module>
<module>appengine/mailjet</module>
<module>appengine/memcache</module>
<module>appengine/oauth2</module>
<module>appengine/sendgrid</module>
<module>appengine/static-files</module>
<module>appengine/twilio</module>
Expand Down

0 comments on commit bd070d9

Please sign in to comment.