[DEV] [NEED TEST] Implement OAuth2 authentification to mail recovery!
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
package fr.xephi.authme.mail;
|
||||
|
||||
import java.security.Provider;
|
||||
|
||||
/* Copyright 2012 Google Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public class OAuth2Provider extends Provider {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public OAuth2Provider() {
|
||||
super("Google OAuth2 Provider", 1.0,
|
||||
"Provides the XOAUTH2 SASL Mechanism");
|
||||
put("SaslClientFactory.XOAUTH2",
|
||||
"fr.xephi.authme.mail.OAuth2SaslClientFactory");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/* Copyright 2012 Google Inc.
|
||||
*
|
||||
* 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 fr.xephi.authme.mail;
|
||||
|
||||
import java.io.IOException;
|
||||
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.UnsupportedCallbackException;
|
||||
import javax.security.sasl.SaslClient;
|
||||
import javax.security.sasl.SaslException;
|
||||
|
||||
/**
|
||||
* An OAuth2 implementation of SaslClient.
|
||||
*/
|
||||
class OAuth2SaslClient implements SaslClient {
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(OAuth2SaslClient.class.getName());
|
||||
|
||||
private final String oauthToken;
|
||||
private final CallbackHandler callbackHandler;
|
||||
|
||||
private boolean isComplete = false;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the OAuth2SaslClient. This will ordinarily only
|
||||
* be called from OAuth2SaslClientFactory.
|
||||
*/
|
||||
public OAuth2SaslClient(String oauthToken,
|
||||
CallbackHandler callbackHandler) {
|
||||
this.oauthToken = oauthToken;
|
||||
this.callbackHandler = callbackHandler;
|
||||
}
|
||||
|
||||
public String getMechanismName() {
|
||||
return "XOAUTH2";
|
||||
}
|
||||
|
||||
public boolean hasInitialResponse() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
|
||||
if (isComplete) {
|
||||
// Empty final response from server, just ignore it.
|
||||
return new byte[] { };
|
||||
}
|
||||
|
||||
NameCallback nameCallback = new NameCallback("Enter name");
|
||||
Callback[] callbacks = new Callback[] { nameCallback };
|
||||
try {
|
||||
callbackHandler.handle(callbacks);
|
||||
} catch (UnsupportedCallbackException e) {
|
||||
throw new SaslException("Unsupported callback: " + e);
|
||||
} catch (IOException e) {
|
||||
throw new SaslException("Failed to execute callback: " + e);
|
||||
}
|
||||
String email = nameCallback.getName();
|
||||
|
||||
byte[] response = String.format("user=%s\1auth=Bearer %s\1\1", email,
|
||||
oauthToken).getBytes();
|
||||
isComplete = true;
|
||||
return response;
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return isComplete;
|
||||
}
|
||||
|
||||
public byte[] unwrap(byte[] incoming, int offset, int len)
|
||||
throws SaslException {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public byte[] wrap(byte[] outgoing, int offset, int len)
|
||||
throws SaslException {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public Object getNegotiatedProperty(String propName) {
|
||||
if (!isComplete()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void dispose() throws SaslException {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Copyright 2012 Google Inc.
|
||||
*
|
||||
* 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 fr.xephi.authme.mail;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.sasl.SaslClient;
|
||||
import javax.security.sasl.SaslClientFactory;
|
||||
|
||||
/**
|
||||
* A SaslClientFactory that returns instances of OAuth2SaslClient.
|
||||
*
|
||||
* <p>Only the "XOAUTH2" mechanism is supported. The {@code callbackHandler} is
|
||||
* passed to the OAuth2SaslClient. Other parameters are ignored.
|
||||
*/
|
||||
public class OAuth2SaslClientFactory implements SaslClientFactory {
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(OAuth2SaslClientFactory.class.getName());
|
||||
|
||||
public static final String OAUTH_TOKEN_PROP =
|
||||
"mail.imaps.sasl.mechanisms.oauth2.oauthToken";
|
||||
|
||||
public SaslClient createSaslClient(String[] mechanisms,
|
||||
String authorizationId,
|
||||
String protocol,
|
||||
String serverName,
|
||||
Map<String, ?> props,
|
||||
CallbackHandler callbackHandler) {
|
||||
boolean matchedMechanism = false;
|
||||
for (int i = 0; i < mechanisms.length; ++i) {
|
||||
if ("XOAUTH2".equalsIgnoreCase(mechanisms[i])) {
|
||||
matchedMechanism = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matchedMechanism) {
|
||||
logger.info("Failed to match any mechanisms");
|
||||
return null;
|
||||
}
|
||||
return new OAuth2SaslClient((String) props.get(OAUTH_TOKEN_PROP),
|
||||
callbackHandler);
|
||||
}
|
||||
|
||||
public String[] getMechanismNames(Map<String, ?> props) {
|
||||
return new String[] {"XOAUTH2"};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package fr.xephi.authme.mail;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.ImageGenerator;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
|
||||
import org.apache.commons.mail.DefaultAuthenticator;
|
||||
import org.apache.commons.mail.EmailException;
|
||||
import org.apache.commons.mail.HtmlEmail;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.sun.mail.smtp.SMTPTransport;
|
||||
|
||||
import javax.activation.DataSource;
|
||||
import javax.activation.FileDataSource;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.mail.Transport;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
|
||||
/**
|
||||
* @author Xephi59
|
||||
* @version $Revision: 1.0 $
|
||||
*/
|
||||
public class SendMailSSL {
|
||||
|
||||
public final AuthMe plugin;
|
||||
|
||||
/**
|
||||
* Constructor for SendMailSSL.
|
||||
*
|
||||
* @param plugin AuthMe
|
||||
*/
|
||||
public SendMailSSL(AuthMe plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method main.
|
||||
*
|
||||
* @param auth PlayerAuth
|
||||
* @param newPass String
|
||||
*/
|
||||
public void main(final PlayerAuth auth, final String newPass) {
|
||||
String senderName;
|
||||
|
||||
if (Settings.getmailSenderName == null || Settings.getmailSenderName.isEmpty()) {
|
||||
senderName = Settings.getmailAccount;
|
||||
} else {
|
||||
senderName = Settings.getmailSenderName;
|
||||
}
|
||||
|
||||
final String sender = senderName;
|
||||
final int port = Settings.getMailPort;
|
||||
final String acc = Settings.getmailAccount;
|
||||
final String subject = Settings.getMailSubject;
|
||||
final String smtp = Settings.getmailSMTP;
|
||||
final String password = Settings.getmailPassword;
|
||||
final String mailText = Settings.getMailText.replace("<playername />", auth.getNickname()).replace("<servername />", plugin.getServer().getServerName()).replace("<generatedpass />", newPass);
|
||||
final String mail = auth.getEmail();
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
|
||||
HtmlEmail email = new HtmlEmail();
|
||||
email.setSmtpPort(port);
|
||||
email.setHostName(smtp);
|
||||
email.addTo(mail);
|
||||
email.setFrom(acc, sender);
|
||||
email.setSubject(subject);
|
||||
if (acc != null && !acc.isEmpty() && password != null && !password.isEmpty())
|
||||
email.setAuthenticator(new DefaultAuthenticator(acc, !Settings.emailOauth2Token.isEmpty() ? "" : password));
|
||||
switch (port) {
|
||||
case 587:
|
||||
email.setStartTLSEnabled(true);
|
||||
email.setStartTLSRequired(true);
|
||||
if (!Settings.emailOauth2Token.isEmpty())
|
||||
{
|
||||
if (Security.getProvider("Google OAuth2 Provider") == null)
|
||||
Security.addProvider(new OAuth2Provider());
|
||||
email.getMailSession().getProperties().setProperty("mail.smtp.starttls.enable", "true");
|
||||
email.getMailSession().getProperties().setProperty("mail.smtp.starttls.required", "true");
|
||||
email.getMailSession().getProperties().setProperty("mail.smtp.sasl.enable", "true");
|
||||
email.getMailSession().getProperties().setProperty("mail.smtp.sasl.mechanisms", "XOAUTH2");
|
||||
email.getMailSession().getProperties().setProperty(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, password);
|
||||
}
|
||||
break;
|
||||
case 25:
|
||||
email.setStartTLSEnabled(true);
|
||||
email.setSSLCheckServerIdentity(true);
|
||||
break;
|
||||
case 465:
|
||||
email.setSSLOnConnect(true);
|
||||
email.setSSLCheckServerIdentity(true);
|
||||
break;
|
||||
default:
|
||||
email.setStartTLSEnabled(true);
|
||||
email.setSSLOnConnect(true);
|
||||
email.setSSLCheckServerIdentity(true);
|
||||
break;
|
||||
}
|
||||
String content = mailText;
|
||||
// Generate an image ?
|
||||
File file = null;
|
||||
if (Settings.generateImage) {
|
||||
try {
|
||||
ImageGenerator gen = new ImageGenerator(newPass);
|
||||
file = new File(plugin.getDataFolder() + File.separator + auth.getNickname() + "_new_pass.jpg");
|
||||
ImageIO.write(gen.generateImage(), "jpg", file);
|
||||
DataSource source = new FileDataSource(file);
|
||||
String tag = email.embed(source, auth.getNickname() + "_new_pass.jpg");
|
||||
content = content.replace("%image%", "<img src=\"cid:" + tag + "\">");
|
||||
} catch (Exception e) {
|
||||
ConsoleLogger.showError("Unable to send new password as image! Using normal text! Dest: " + mail);
|
||||
}
|
||||
}
|
||||
try {
|
||||
email.setHtmlMsg(content);
|
||||
email.setTextMsg(content);
|
||||
} catch (EmailException e)
|
||||
{
|
||||
ConsoleLogger.showError("Your email.html config contains some error and cannot be send!");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (!Settings.emailOauth2Token.isEmpty())
|
||||
{
|
||||
SMTPTransport.send(email.getMimeMessage(), acc, "");
|
||||
}
|
||||
else
|
||||
SMTPTransport.send(email.getMimeMessage());
|
||||
} catch (Exception e) {
|
||||
ConsoleLogger.showError("Fail to send a mail to " + mail + " cause " + e.getLocalizedMessage());
|
||||
}
|
||||
if (file != null)
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
file.delete();
|
||||
|
||||
} catch (Exception e) {
|
||||
// Print the stack trace
|
||||
e.printStackTrace();
|
||||
ConsoleLogger.showError("Some error occurred while trying to send a email to " + mail);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user