Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/build-jar.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path

name: gmail-oauth2-tools

on: push

jobs:
build:

runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }}/java # location for the settings.xml file

- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Test with Maven
run: mvn test --file pom.xml
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/
.vscode/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![gmail-oauth2-tools](https://github.com/FreedomFaighter/gmail-oauth2-tools/actions/workflows/build-jar.yml/badge.svg)](https://github.com/FreedomFaighter/gmail-oauth2-tools/actions/workflows/build-jar.yml)

Tools and sample code for authenticating to Gmail with OAuth2.

The specification is available [here](https://developers.google.com/gmail/xoauth2_protocol).
Expand Down
5 changes: 3 additions & 2 deletions go/sendgmail/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ send-email`.
* Follow the steps in the **Authorize credentials for a desktop
application** section. However, set the application type to *Web
application* (i.e. instead of *Desktop app*) and then add
`https://oauth2.dance/` as an authorised redirect URI. This is necessary
for seeing the authorisation code on a page in your browser.
`https://google.github.io/gmail-oauth2-tools/html/oauth2.dance.html`
as an authorised redirect URI. This is necessary for seeing the
authorisation code on a page in your browser.

* When you download the credentials as JSON, create the
`${XDG_CONFIG_HOME:-${HOME}/.config}/sendgmail` directory with file mode
Expand Down
30 changes: 30 additions & 0 deletions html/oauth2.dance.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>:root { color-scheme: dark light; }</style>
<title>oauth2.dance</title>
<h1>oauth2.dance</h1>
<div id="authCodeDivFailure" style="display: none;">
These aren't the droids you're looking for.
</div>
<div id="authCodeDivSuccess" style="display: none;">
Authorisation Code:
<span id="authCodeSpan" style="font-family: monospace; font-weight: bold;"></span>
<br>
<button id="authCodeButton">Copy To Clipboard</button>
</div>
<script>
var searchParams = new URLSearchParams(window.location.search);
var code = searchParams.get("code");
if (code === null) {
var div = document.getElementById("authCodeDivFailure");
div.style = "";
} else {
var button = document.getElementById("authCodeButton");
button.addEventListener("click", (e) => { navigator.clipboard.writeText(code); });
var span = document.getElementById("authCodeSpan");
span.textContent = code;
var div = document.getElementById("authCodeDivSuccess");
div.style = "";
}
</script>
70 changes: 0 additions & 70 deletions java/build-java-sample-zip.sh

This file was deleted.

34 changes: 0 additions & 34 deletions java/build.properties

This file was deleted.

58 changes: 0 additions & 58 deletions java/build.xml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* limitations under the License.
*/

package com.google.code.samples.oauth2;
package main.com.google.code.samples.oauth2;

import com.sun.mail.imap.IMAPStore;
import com.sun.mail.imap.IMAPSSLStore;
Expand All @@ -39,7 +39,7 @@ public class OAuth2Authenticator {
Logger.getLogger(OAuth2Authenticator.class.getName());

public static final class OAuth2Provider extends Provider {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 454502445710734267L;

public OAuth2Provider() {
super("Google OAuth2 Provider", 1.0,
Expand Down Expand Up @@ -147,7 +147,7 @@ public static void main(String args[]) throws Exception {
email,
oauthToken,
true);
System.out.println("Successfully authenticated to IMAP.\n");
System.out.print("Successfully authenticated to IMAP.\n\n");
SMTPTransport smtpTransport = connectToSmtp("smtp.gmail.com",
587,
email,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@
* limitations under the License.
*/

package com.google.code.samples.oauth2;
package main.com.google.code.samples.oauth2;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.logging.Logger;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslException;

import org.apache.maven.surefire.shared.lang3.NotImplementedException;


/**
* An OAuth2 implementation of SaslClient.
Expand All @@ -39,7 +39,8 @@ class OAuth2SaslClient implements SaslClient {
private final CallbackHandler callbackHandler;

private boolean isComplete = false;

private String MechanismName = "XOAUTH2";
private String Email;
/**
* Creates a new instance of the OAuth2SaslClient. This will ordinarily only
* be called from OAuth2SaslClientFactory.
Expand All @@ -50,8 +51,14 @@ public OAuth2SaslClient(String oauthToken,
this.callbackHandler = callbackHandler;
}

public OAuth2SaslClient()
{
this.oauthToken = null;
this.callbackHandler = null;
}

public String getMechanismName() {
return "XOAUTH2";
return this.MechanismName;
}

public boolean hasInitialResponse() {
Expand All @@ -73,12 +80,12 @@ public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
} catch (IOException e) {
throw new SaslException("Failed to execute callback: " + e);
}
String email = nameCallback.getName();
this.Email = nameCallback.getName();

byte[] response = String.format("user=%s\1auth=Bearer %s\1\1", email,
byte[] postToAppendToServerAddress = String.format("user=%s\1auth=Bearer %s\1\1", this.Email,
oauthToken).getBytes();
isComplete = true;
return response;
return postToAppendToServerAddress;
}

public boolean isComplete() {
Expand All @@ -87,19 +94,43 @@ public boolean isComplete() {

public byte[] unwrap(byte[] incoming, int offset, int len)
throws SaslException {
throw new IllegalStateException();
throw new NotImplementedException();
}

public byte[] wrap(byte[] outgoing, int offset, int len)
throws SaslException {
throw new IllegalStateException();
throw new NotImplementedException();
}

public Object getNegotiatedProperty(String propName) {
if (!isComplete()) {
throw new IllegalStateException();
}
return null;
switch(propName)
{
case "Email":
if(this.Email == null)
return null;
else
return this.Email;
case "MechanismName":
if(this.MechanismName == null)
return null;
else
return this.getMechanismName();
case "OAuthToken":
if(null == this.oauthToken)
return null;
else
return this.oauthToken;
case "CallbackHandler":
if(this.callbackHandler == null)
return null;
else
return this.callbackHandler;
default:
return null;
}
}

public void dispose() throws SaslException {
Expand Down
Loading