├── settings.gradle ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ └── java │ └── net │ └── chris54721 │ └── openmcauthenticator │ ├── exceptions │ ├── InvalidTokenException.java │ ├── AuthenticationUnavailableException.java │ ├── InvalidCredentialsException.java │ ├── UserMigratedException.java │ └── RequestException.java │ ├── responses │ ├── RefreshResponse.java │ ├── RequestResponse.java │ ├── AuthenticationResponse.java │ ├── ErrorResponse.java │ └── LoginResponse.java │ ├── Profile.java │ ├── JsonUtils.java │ └── OpenMCAuthenticator.java ├── LICENSE.md ├── gradlew.bat ├── gradlew └── README.md /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'openmcauthenticator' 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ IDEA 2 | .idea/ 3 | *.iml 4 | 5 | # Gradle 6 | .gradle 7 | build 8 | gradle.properties 9 | !gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chris54721/OpenMCAuthenticator/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Mar 15 15:39:20 CET 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip 7 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/exceptions/InvalidTokenException.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator.exceptions; 2 | 3 | import net.chris54721.openmcauthenticator.responses.ErrorResponse; 4 | 5 | /** 6 | * Thrown when the provided token is invalid or expired. 7 | */ 8 | public class InvalidTokenException extends RequestException { 9 | 10 | public InvalidTokenException(ErrorResponse error) { 11 | super(error); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/exceptions/AuthenticationUnavailableException.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator.exceptions; 2 | 3 | import net.chris54721.openmcauthenticator.responses.ErrorResponse; 4 | 5 | /** 6 | * Thrown when the authentication servers are unreachable. 7 | */ 8 | public class AuthenticationUnavailableException extends Exception { 9 | 10 | public AuthenticationUnavailableException(ErrorResponse error) { 11 | 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/exceptions/InvalidCredentialsException.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator.exceptions; 2 | 3 | import net.chris54721.openmcauthenticator.responses.ErrorResponse; 4 | 5 | /** 6 | * Thrown when the provided username/password pair is wrong or empty. 7 | */ 8 | public class InvalidCredentialsException extends RequestException { 9 | 10 | public InvalidCredentialsException(ErrorResponse error) { 11 | super(error); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/exceptions/UserMigratedException.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator.exceptions; 2 | 3 | import net.chris54721.openmcauthenticator.responses.ErrorResponse; 4 | 5 | /** 6 | * Thrown when a nickname is used as username instead of an email address and the user has a Mojang account. 7 | */ 8 | public class UserMigratedException extends RequestException { 9 | 10 | public UserMigratedException(ErrorResponse error) { 11 | super(error); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/responses/RefreshResponse.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator.responses; 2 | 3 | import net.chris54721.openmcauthenticator.Profile; 4 | 5 | /** 6 | * Response generated when refresh is successful. 7 | * 8 | * @see LoginResponse 9 | */ 10 | public class RefreshResponse extends LoginResponse { 11 | 12 | public RefreshResponse(String accessToken, String clientToken, Profile selectedProfile) { 13 | super(accessToken, clientToken, selectedProfile); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/Profile.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator; 2 | 3 | import java.io.Serializable; 4 | import java.util.UUID; 5 | 6 | public class Profile implements Serializable { 7 | 8 | private String id; 9 | private String name; 10 | private boolean legacy; 11 | 12 | public Profile(String id, String name, boolean legacy) { 13 | this.id = id; 14 | this.name = name; 15 | this.legacy = legacy; 16 | } 17 | 18 | public UUID getUUID() { 19 | return UUID.fromString(id.replaceAll("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")); 20 | } 21 | 22 | public String getName() { 23 | return name; 24 | } 25 | 26 | public boolean isLegacy() { 27 | return legacy; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/responses/RequestResponse.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator.responses; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Base class for API responses. 7 | */ 8 | public class RequestResponse { 9 | 10 | private int responseCode = -1; 11 | private Map data; 12 | 13 | public RequestResponse(int responseCode, Map data) { 14 | this.responseCode = responseCode; 15 | this.data = data; 16 | } 17 | 18 | public int getResponseCode() { 19 | return responseCode; 20 | } 21 | 22 | public boolean isSuccessful() { 23 | return responseCode == 200 || responseCode == 204; 24 | } 25 | 26 | public Map getData() { 27 | return data; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/responses/AuthenticationResponse.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator.responses; 2 | 3 | import net.chris54721.openmcauthenticator.Profile; 4 | 5 | /** 6 | * Response generated when authentication is successful. 7 | * 8 | * @see LoginResponse 9 | */ 10 | public class AuthenticationResponse extends LoginResponse { 11 | 12 | private Profile[] availableProfiles; 13 | 14 | public AuthenticationResponse(String accessToken, String clientToken, Profile selectedProfile, Profile[] availableProfiles) { 15 | super(accessToken, clientToken, selectedProfile); 16 | this.availableProfiles = availableProfiles; 17 | } 18 | 19 | public Profile[] getAvailableProfiles() { 20 | return availableProfiles; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/responses/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator.responses; 2 | 3 | import java.io.Serializable; 4 | import net.chris54721.openmcauthenticator.exceptions.RequestException; 5 | 6 | /** 7 | * Response generated when an exception is thrown. 8 | * Intended for internal use only. 9 | * Call getError() and getErrorMessage() on a RequestException object to get more info about the error. 10 | * 11 | * @see RequestException 12 | */ 13 | public class ErrorResponse implements Serializable { 14 | 15 | private String error; 16 | private String errorMessage; 17 | private String cause; 18 | 19 | public String getError() { 20 | return error; 21 | } 22 | 23 | public String getErrorMessage() { 24 | return errorMessage; 25 | } 26 | 27 | public String getCause() { 28 | return cause; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/responses/LoginResponse.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator.responses; 2 | 3 | import net.chris54721.openmcauthenticator.Profile; 4 | 5 | /** 6 | * Response generated when authentication/refresh is successful. 7 | * 8 | * @see LoginResponse 9 | */ 10 | public class LoginResponse { 11 | 12 | private String accessToken; 13 | private String clientToken; 14 | private Profile selectedProfile; 15 | 16 | public LoginResponse(String accessToken, String clientToken, Profile selectedProfile) { 17 | this.accessToken = accessToken; 18 | this.clientToken = clientToken; 19 | this.selectedProfile = selectedProfile; 20 | } 21 | 22 | public String getAccessToken() { 23 | return accessToken; 24 | } 25 | 26 | public String getClientToken() { 27 | return clientToken; 28 | } 29 | 30 | public Profile getSelectedProfile() { 31 | return selectedProfile; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/exceptions/RequestException.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator.exceptions; 2 | 3 | import net.chris54721.openmcauthenticator.responses.ErrorResponse; 4 | 5 | /** 6 | * Main class, extended by every library's exception. 7 | * 8 | * @see AuthenticationUnavailableException 9 | * @see InvalidCredentialsException 10 | * @see InvalidTokenException 11 | * @see UserMigratedException 12 | */ 13 | public class RequestException extends Exception { 14 | 15 | private ErrorResponse error; 16 | 17 | public RequestException(ErrorResponse error) { 18 | this.error = error; 19 | } 20 | 21 | public ErrorResponse getResponse() { 22 | return this.error; 23 | } 24 | 25 | public String getError() { 26 | return this.error.getError(); 27 | } 28 | 29 | public String getErrorMessage() { 30 | return this.error.getErrorMessage(); 31 | } 32 | 33 | public String getErrorCause() { 34 | return this.error.getCause(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Chris54721 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without 6 | limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 7 | Software, and to permit persons to whom the Software is furnished to do so, subject to the following 8 | conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 11 | of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 14 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 16 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 17 | DEALINGS IN THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.reflect.TypeToken; 5 | import java.lang.reflect.Type; 6 | import java.util.LinkedHashMap; 7 | import java.util.Map; 8 | 9 | public class JsonUtils { 10 | 11 | public static Gson gson; 12 | public static Type stringObjectMap; 13 | private static final Map MINECRAFT_AGENT = new LinkedHashMap(); 14 | 15 | static { 16 | gson = new Gson(); 17 | stringObjectMap = new TypeToken>() { 18 | }.getType(); 19 | Map agentValues = new LinkedHashMap(); 20 | agentValues.put("name", "Minecraft"); 21 | agentValues.put("version", 1); 22 | MINECRAFT_AGENT.put("agent", agentValues); 23 | } 24 | 25 | public static String credentialsToJson(String username, String password, String clientToken) { 26 | Map jsonData = new LinkedHashMap(); 27 | jsonData.putAll(MINECRAFT_AGENT); 28 | jsonData.put("username", username); 29 | jsonData.put("password", password); 30 | if (clientToken != null) { 31 | jsonData.put("clientToken", clientToken); 32 | } 33 | return gson.toJson(jsonData); 34 | } 35 | 36 | public static String tokenToJson(String authToken, String clientToken) { 37 | Map jsonData = new LinkedHashMap(); 38 | jsonData.put("accessToken", authToken); 39 | if (clientToken != null) { 40 | jsonData.put("clientToken", clientToken); 41 | } 42 | return gson.toJson(jsonData); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OpenMCAuthenticator 2 | =================== 3 | [![Release](https://jitpack.io/v/chris54721/OpenMCAuthenticator.svg)](https://jitpack.io/#chris54721/OpenMCAuthenticator) 4 | 5 | A simple, open and documented Java API for Minecraft authentication. 6 | 7 | ## Features 8 | - Works with both Mojang and old Minecraft accounts 9 | - Provides methods for every endpoint 10 | - Custom exceptions for error reporting 11 | 12 | ## Installation 13 | Just add this to your `build.gradle`: 14 | ``` 15 | repositories { 16 | jcenter() 17 | maven { url "https://jitpack.io" } 18 | } 19 | 20 | dependencies { 21 | compile 'com.github.chris54721:openmcauthenticator:1.3.1' 22 | } 23 | ``` 24 | 25 | ## Usage 26 | The library uses mainly static methods. You won't have to instantiate anything. Just call the static methods in the class `OpenMCAuthenticator` with the required arguments to get your response. 27 | 28 | The available methods are: `authenticate`, `refresh`, `signout`, `validate` and `invalidate`. 29 | 30 | `authenticate` and `refresh` return a response object extending `LoginResponse` (`AuthenticationResponse` or `RefreshResponse`). This means, regardless of the method used, you will be able to use the following methods: 31 | - `getAccessToken` - returns the access token to be used when launching the game 32 | - `getClientToken` - returns the client token used in the request 33 | - `getSelectedProfile` - returns a Profile object representing the current profile 34 | 35 | For a more detailed documentation, just check the javadoc included with the library. 36 | 37 | ### Profiles 38 | The `Profile` object is returned by `loginResponse.getSelectedProfile()` and a `Profile[]` object is returned by `authenticationResponse.getAvailableProfiles()` (where `loginResponse` and `authenticationResponse` are instances of the two classes). It contains the following (non-static) methods: 39 | - `getUUID()` - returns the user's UUID. Can be converted to a string with `toString()` 40 | - `getName()` - returns the nickname of the user with correct capitalization as a `String` 41 | - `isLegacy()` - returns a boolean; `true` if the profile is a legacy (old) Minecraft account (uses username to log in) 42 | 43 | ### Exceptions 44 | Every available method throws an exception extending `RequestException` if the request returned an authentication problem. 45 | The full list of exceptions is available below. 46 | - `RequestException` - a general exception. Every other authentication exception extends this. To get more detailed info about the exception, call `getError()` or `getErrorMessage()`. 47 | - `InvalidCredentialsException` - the provided credentials are invalid (bad or empty username/password). Thrown by `authenticate` and `signout`. 48 | - `InvalidTokenException` - the provided token is invalid. Thrown by `refresh`, `validate` and `invalidate`. 49 | - `UserMigratedException` - the Mojang account email address should be used as the username instead of the nickname. Thrown by `authenticate` and `signout`. 50 | - `AuthenticationUnavailableException` - thrown every time an `IOException` is generated, so every time the authentication services are unavailable. Does not extend `RequestException` as there's no error code. 51 | 52 | #### Exceptions example 53 | ``` 54 | try { 55 | // make request 56 | } catch (RequestException e) { 57 | if (e instanceof AuthenticationUnavailableException) { 58 | // Authentication servers unavailable 59 | } 60 | if (e instanceof InvalidCredentialsException) { 61 | // Bad username or password 62 | } 63 | } 64 | ``` 65 | 66 | ### Authentication 67 | Use `OpenMCAuthenticator.authenticate` to request authentication with an username and a password. 68 | ``` 69 | try { 70 | AuthenticationResponse authResponse = OpenMCAuthenticator.authenticate("username", "password"); 71 | String authToken = authResponse.getAccessToken(); 72 | } catch (RequestException e) { 73 | // handle exception 74 | } 75 | ``` 76 | 77 | ### Refresh 78 | Use `OpenMCAuthenticator.refresh` to request a new token by providing a valid one and the client token used to get the token in the first place. 79 | **The token has to be the same to the one returned when getting the access token!** See the [Client tokens](https://github.com/Chris54721/OpenMCAuthenticator#client-tokens) section for more info. 80 | ``` 81 | try { 82 | RefreshResponse refreshResponse = OpenMCAuthenticator.refresh("old accessToken", "used clientToken"); 83 | String authToken = refreshResponse.getAccessToken(); 84 | } catch (RequestException e) { 85 | // handle exception 86 | } 87 | ``` 88 | 89 | ### Validate 90 | Use `OpenMCAuthenticator.validate` to check if the provided access token represents the latest active session. 91 | **This will return true only if the token is the most recently generated.** It's intended to be used by servers to check if the player is not logged in elsewhere with a new access token. 92 | ``` 93 | try { 94 | boolean isValid = OpenMCAuthenticator.validate("accessToken"); 95 | } catch (RequestException e) { 96 | // handle exception 97 | } 98 | ``` 99 | 100 | ### Invalidate 101 | Use `OpenMCAuthenticator.invalidate` to invalidate the given access token. 102 | **The client token has to be the same to the one returned when getting the access token!** See the [Client tokens](https://github.com/Chris54721/OpenMCAuthenticator#client-tokens) section for more info. 103 | ``` 104 | try { 105 | boolean success = OpenMCAuthenticator.invalidate("accessToken", "clientToken"); 106 | } catch (RequestException e) { 107 | // handle exception 108 | } 109 | ``` 110 | 111 | ### Signout 112 | Use `OpenMCAuthenticator.signout` to invalidate *every* access token for an user by providing its username and password. 113 | ``` 114 | try { 115 | boolean success = OpenMCAuthenticator.signout("username", "password"); 116 | } catch (RequestException e) { 117 | // handle exception 118 | } 119 | ``` 120 | 121 | ### Client tokens 122 | The `clientToken` value is intended to be generated randomly for `authenticate`, `signout` and `validate` (while `request` and `invalidate` require it to be the same to the one received when getting the token) 123 | 124 | OpenMCAuthenticator by default doesn't send a client token when optional, as the authentication servers automatically generate one (by default a random UUID, which is then obtainable by the client by calling `getClientToken()` on the returned `LoginResponse`). If for some reason you need to use a custom client token, just add it as a `String` to the request method parameters. For example: 125 | ``` 126 | // Default (the server will generate the token) 127 | OpenMCAuthenticator.authenticate("username", "password"); 128 | 129 | // Send a new random UUID generated by the client as the token 130 | OpenMCAuthenticator.authenticate("username", "password", UUID.randomUUID().toString()); 131 | 132 | // Send a randomly generated secure session identifier (random 32-chars string) 133 | String token = new BigInteger(130, new SecureRandom()).toString(32); 134 | OpenMCAuthenticator.authenticate("username", "password", token); 135 | ``` 136 | 137 | ## Reporting issues 138 | If you found an issue in the API, just [click here](https://github.com/Chris54721/OpenMCAuthenticator/issues/new) to report it! 139 | Try to be as accurate as possible and add some steps to reproduce the issue. 140 | -------------------------------------------------------------------------------- /src/main/java/net/chris54721/openmcauthenticator/OpenMCAuthenticator.java: -------------------------------------------------------------------------------- 1 | package net.chris54721.openmcauthenticator; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | import java.io.OutputStream; 6 | import java.net.Proxy; 7 | import java.net.URL; 8 | import java.util.Map; 9 | import javax.net.ssl.HttpsURLConnection; 10 | import net.chris54721.openmcauthenticator.exceptions.AuthenticationUnavailableException; 11 | import net.chris54721.openmcauthenticator.exceptions.InvalidCredentialsException; 12 | import net.chris54721.openmcauthenticator.exceptions.InvalidTokenException; 13 | import net.chris54721.openmcauthenticator.exceptions.RequestException; 14 | import net.chris54721.openmcauthenticator.exceptions.UserMigratedException; 15 | import net.chris54721.openmcauthenticator.responses.AuthenticationResponse; 16 | import net.chris54721.openmcauthenticator.responses.ErrorResponse; 17 | import net.chris54721.openmcauthenticator.responses.RefreshResponse; 18 | import net.chris54721.openmcauthenticator.responses.RequestResponse; 19 | 20 | /** 21 | * OpenMCAuthenticator - Simple Minecraft authenticator 22 | * 23 | * @author Chris54721 24 | * @version 1.3.1 25 | * @see OpenMCAuthenticator on GitHub 26 | */ 27 | public class OpenMCAuthenticator { 28 | 29 | /** 30 | * Authenticates an user with an username and a password. 31 | * Allows to send a custom client token with the request. 32 | * 33 | * @param username The username, can be a nickname (old Minecraft account) or an email (Mojang account) 34 | * @param password The password for the account 35 | * @param clientToken Custom client token to be sent with the request (should be unique) 36 | * @param proxy A proxy to use when making the HTTP request 37 | * @return An AuthenticationResponse containing the server response 38 | * @throws AuthenticationUnavailableException the servers are unreachable 39 | * @throws InvalidCredentialsException bad or empty username/password pair 40 | * @throws UserMigratedException email should be used as username instead of nickname 41 | * @see OpenMCAuthenticator#authenticate(String username, String password) 42 | * @see OpenMCAuthenticator#authenticate(String username, String password, String clientToken) 43 | */ 44 | public static AuthenticationResponse authenticate(String username, String password, String clientToken, Proxy proxy) throws RequestException, AuthenticationUnavailableException { 45 | RequestResponse result = sendJsonPostRequest(getRequestUrl("authenticate"), JsonUtils.credentialsToJson(username, password, clientToken), proxy); 46 | if (result.isSuccessful()) { 47 | String accessToken = (String) result.getData().get("accessToken"); 48 | String rClientToken = (String) result.getData().get("clientToken"); 49 | Profile selectedProfile = JsonUtils.gson.fromJson(JsonUtils.gson.toJson(result.getData().get("selectedProfile")), Profile.class); 50 | Profile[] availableProfiles = JsonUtils.gson.fromJson(JsonUtils.gson.toJson(result.getData().get("availableProfiles")), Profile[].class); 51 | return new AuthenticationResponse(accessToken, rClientToken, selectedProfile, availableProfiles); 52 | } else { 53 | ErrorResponse errorResponse = JsonUtils.gson.fromJson(JsonUtils.gson.toJson(result.getData()), ErrorResponse.class); 54 | if (result.getData().get("cause") != null && ((String) (result.getData().get("cause"))).equalsIgnoreCase("UserMigratedException")) { 55 | throw new UserMigratedException(errorResponse); 56 | } else { 57 | throw new InvalidCredentialsException(errorResponse); 58 | } 59 | } 60 | } 61 | 62 | /** 63 | * Authenticates an user with an username and a password. 64 | * The server will generate a random client token. 65 | * 66 | * @param username The username, can be a nickname (old Minecraft account) or an email (Mojang account) 67 | * @param password The password for the account 68 | * @param clientToken Custom client token to be sent with the request (should be unique) 69 | * @return An AuthenticationResponse containing the server response 70 | * @throws AuthenticationUnavailableException the servers are unreachable 71 | * @throws InvalidCredentialsException bad or empty username/password pair 72 | * @throws UserMigratedException email should be used as username instead of nickname 73 | * @see OpenMCAuthenticator#authenticate(String username, String password, String clientToken, Proxy proxy) 74 | * @see OpenMCAuthenticator#authenticate(String username, String password) 75 | */ 76 | public static AuthenticationResponse authenticate(String username, String password, String clientToken) throws RequestException, AuthenticationUnavailableException { 77 | return authenticate(username, password, clientToken, null); 78 | } 79 | 80 | /** 81 | * Authenticates an user with an username and a password. 82 | * The server will generate a random client token. 83 | * 84 | * @param username The username, can be a nickname (old Minecraft account) or an email (Mojang account) 85 | * @param password The password for the account 86 | * @return An AuthenticationResponse containing the server response 87 | * @throws AuthenticationUnavailableException the servers are unreachable 88 | * @throws InvalidCredentialsException bad or empty username/password pair 89 | * @throws UserMigratedException email should be used as username instead of nickname 90 | * @see OpenMCAuthenticator#authenticate(String username, String password, String clientToken) 91 | * @see OpenMCAuthenticator#authenticate(String username, String password, String clientToken, Proxy proxy) 92 | */ 93 | public static AuthenticationResponse authenticate(String username, String password) throws RequestException, AuthenticationUnavailableException { 94 | return authenticate(username, password, null, null); 95 | } 96 | 97 | /** 98 | * Refreshes the given access token. 99 | * 100 | * @param accessToken The authentication token to be refreshed 101 | * @param clientToken Client token to be sent with the request. Needs to be identical to the one received when getting the token. 102 | * @param proxy A proxy to use when making the HTTP request 103 | * @return A RefreshResponse containing the server response 104 | * @throws AuthenticationUnavailableException the servers are unreachable 105 | * @throws InvalidTokenException the provided token is invalid 106 | * @see OpenMCAuthenticator#refresh(String accessToken, String clientToken) 107 | */ 108 | public static RefreshResponse refresh(String accessToken, String clientToken, Proxy proxy) throws RequestException, AuthenticationUnavailableException { 109 | RequestResponse result = sendJsonPostRequest(getRequestUrl("refresh"), JsonUtils.tokenToJson(accessToken, clientToken), proxy); 110 | if (result.isSuccessful()) { 111 | String newAccessToken = (String) result.getData().get("accessToken"); 112 | String rClientToken = (String) result.getData().get("clientToken"); 113 | Profile selectedProfile = JsonUtils.gson.fromJson(JsonUtils.gson.toJson(result.getData().get("selectedProfile")), Profile.class); 114 | return new RefreshResponse(newAccessToken, rClientToken, selectedProfile); 115 | } else { 116 | ErrorResponse errorResponse = JsonUtils.gson.fromJson(JsonUtils.gson.toJson(result.getData()), ErrorResponse.class); 117 | throw new InvalidTokenException(errorResponse); 118 | } 119 | } 120 | 121 | /** 122 | * Refreshes the given access token. 123 | * 124 | * @param accessToken The authentication token to be refreshed 125 | * @param clientToken Client token to be sent with the request. Needs to be identical to the one received when getting the token. 126 | * @return A RefreshResponse containing the server response 127 | * @throws AuthenticationUnavailableException the servers are unreachable 128 | * @throws InvalidTokenException the provided token is invalid 129 | * @see OpenMCAuthenticator#refresh(String accessToken, String clientToken, Proxy proxy) 130 | */ 131 | public static RefreshResponse refresh(String accessToken, String clientToken) throws RequestException, AuthenticationUnavailableException { 132 | return refresh(accessToken, clientToken, null); 133 | } 134 | 135 | /** 136 | * Validates the given access token. This will return true only if the token is the most recently generated! 137 | * Allows to send a custom client token with the request. 138 | * 139 | * @param accessToken The authentication token to be validated 140 | * @param clientToken Custom client token to be sent with the request (should be unique) 141 | * @param proxy A proxy to use when making the HTTP request 142 | * @return true if the token is valid, false otherwise. 143 | * @throws AuthenticationUnavailableException the servers are unreachable 144 | * @throws InvalidTokenException the provided token is invalid 145 | * @see OpenMCAuthenticator#validate(String accessToken) 146 | * @see OpenMCAuthenticator#validate(String accessToken, String clientToken) 147 | */ 148 | public static boolean validate(String accessToken, String clientToken, Proxy proxy) throws RequestException, AuthenticationUnavailableException { 149 | RequestResponse result = sendJsonPostRequest(getRequestUrl("validate"), JsonUtils.tokenToJson(accessToken, clientToken), proxy); 150 | if (result.isSuccessful()) { 151 | return true; 152 | } else { 153 | ErrorResponse errorResponse = JsonUtils.gson.fromJson(JsonUtils.gson.toJson(result.getData()), ErrorResponse.class); 154 | throw new InvalidTokenException(errorResponse); 155 | } 156 | } 157 | 158 | /** 159 | * Validates the given access token. This will return true only if the token is the most recently generated! 160 | * Allows to send a custom client token with the request. 161 | * 162 | * @param accessToken The authentication token to be validated 163 | * @param clientToken Custom client token to be sent with the request (should be unique) 164 | * @return true if the token is valid, false otherwise. 165 | * @throws AuthenticationUnavailableException the servers are unreachable 166 | * @throws InvalidTokenException the provided token is invalid 167 | * @see OpenMCAuthenticator#validate(String accessToken) 168 | * @see OpenMCAuthenticator#validate(String accessToken, String clientToken, Proxy proxy) 169 | */ 170 | public static boolean validate(String accessToken, String clientToken) throws RequestException, AuthenticationUnavailableException { 171 | return validate(accessToken, clientToken, null); 172 | } 173 | 174 | /** 175 | * Validates the given access token. This will return true only if the token is the most recently generated! 176 | * The server will generate a random client token. 177 | * 178 | * @param accessToken The authentication token to be validated 179 | * @return true if the token is valid, false otherwise. 180 | * @throws AuthenticationUnavailableException the servers are unreachable 181 | * @throws InvalidTokenException the provided token is invalid 182 | * @see OpenMCAuthenticator#validate(String accessToken, String clientToken) 183 | * @see OpenMCAuthenticator#validate(String accessToken, String clientToken, Proxy proxy) 184 | */ 185 | public static boolean validate(String accessToken) throws RequestException, AuthenticationUnavailableException { 186 | return validate(accessToken, null, null); 187 | } 188 | 189 | /** 190 | * Invalidates the given access token. 191 | * 192 | * @param accessToken The authentication token to be validated 193 | * @param clientToken Client token to be sent with the request. Needs to be identical to the one received when getting the token. 194 | * @param proxy A proxy to use when making the HTTP request 195 | * @return true if the token was invalidated successfully, false otherwise. 196 | * @throws AuthenticationUnavailableException the servers are unreachable 197 | * @throws InvalidTokenException the provided token is invalid 198 | * @see OpenMCAuthenticator#invalidate(String accessToken, String clientToken) 199 | */ 200 | public static boolean invalidate(String accessToken, String clientToken, Proxy proxy) throws RequestException, AuthenticationUnavailableException { 201 | RequestResponse result = sendJsonPostRequest(getRequestUrl("invalidate"), JsonUtils.tokenToJson(accessToken, clientToken), proxy); 202 | if (result.isSuccessful()) { 203 | return true; 204 | } else { 205 | ErrorResponse errorResponse = JsonUtils.gson.fromJson(JsonUtils.gson.toJson(result.getData()), ErrorResponse.class); 206 | throw new InvalidTokenException(errorResponse); 207 | } 208 | } 209 | 210 | /** 211 | * Invalidates the given access token. 212 | * 213 | * @param accessToken The authentication token to be validated 214 | * @param clientToken Client token to be sent with the request. Needs to be identical to the one received when getting the token. 215 | * @return true if the token was invalidated successfully, false otherwise. 216 | * @throws AuthenticationUnavailableException the servers are unreachable 217 | * @throws InvalidTokenException the provided token is invalid 218 | * @see OpenMCAuthenticator#invalidate(String accessToken, String clientToken, Proxy proxy) 219 | */ 220 | public static boolean invalidate(String accessToken, String clientToken) throws RequestException, AuthenticationUnavailableException { 221 | return invalidate(accessToken, clientToken, null); 222 | } 223 | 224 | /** 225 | * Invalidates every access token for an user, by providing username and password 226 | * Allows to send a custom client token with the request. 227 | * 228 | * @param username The username, can be a nickname (old Minecraft account) or an email (Mojang account) 229 | * @param password The password for the account 230 | * @param clientToken Custom client token to be sent with the request (should be unique) 231 | * @param proxy A proxy to use when making the HTTP request 232 | * @return true if the signout request was successful, false otherwise. 233 | * @throws AuthenticationUnavailableException the servers are unreachable 234 | * @throws InvalidCredentialsException bad or empty username/password pair 235 | * @throws UserMigratedException email should be used as username instead of nickname 236 | * @see OpenMCAuthenticator#signout(String username, String password) 237 | */ 238 | public static boolean signout(String username, String password, String clientToken, Proxy proxy) throws RequestException, AuthenticationUnavailableException { 239 | RequestResponse result = sendJsonPostRequest(getRequestUrl("signout"), JsonUtils.credentialsToJson(username, password, clientToken), proxy); 240 | if (result.isSuccessful()) { 241 | return true; 242 | } else { 243 | ErrorResponse errorResponse = JsonUtils.gson.fromJson(JsonUtils.gson.toJson(result.getData()), ErrorResponse.class); 244 | if (result.getData().get("cause") != null && ((String) (result.getData().get("cause"))).equalsIgnoreCase("UserMigratedException")) { 245 | throw new UserMigratedException(errorResponse); 246 | } else { 247 | throw new InvalidCredentialsException(errorResponse); 248 | } 249 | } 250 | } 251 | 252 | /** 253 | * Invalidates every access token for an user, by providing username and password 254 | * Allows to send a custom client token with the request. 255 | * 256 | * @param username The username, can be a nickname (old Minecraft account) or an email (Mojang account) 257 | * @param password The password for the account 258 | * @param clientToken Custom client token to be sent with the request (should be unique) 259 | * @return true if the signout request was successful, false otherwise. 260 | * @throws AuthenticationUnavailableException the servers are unreachable 261 | * @throws InvalidCredentialsException bad or empty username/password pair 262 | * @throws UserMigratedException email should be used as username instead of nickname 263 | * @see OpenMCAuthenticator#signout(String username, String password) 264 | * @see OpenMCAuthenticator#signout(String username, String password, String clientToken, Proxy proxy) 265 | */ 266 | public static boolean signout(String username, String password, String clientToken) throws RequestException, AuthenticationUnavailableException { 267 | return signout(username, password, clientToken, null); 268 | } 269 | 270 | /** 271 | * Invalidates every access token for an user, by providing username and password 272 | * The server will generate a random client token. 273 | * 274 | * @param username The username, can be a nickname (old Minecraft account) or an email (Mojang account) 275 | * @param password The password for the account 276 | * @return true if the signout request was successful, false otherwise. 277 | * @throws AuthenticationUnavailableException the servers are unreachable 278 | * @throws InvalidCredentialsException bad or empty username/password pair 279 | * @throws UserMigratedException email should be used as username instead of nickname 280 | * @see OpenMCAuthenticator#signout(String username, String password, String clientToken) 281 | * @see OpenMCAuthenticator#signout(String username, String password, String clientToken, Proxy proxy) 282 | */ 283 | public static boolean signout(String username, String password) throws RequestException, AuthenticationUnavailableException { 284 | return signout(username, password, null, null); 285 | } 286 | 287 | private static URL getRequestUrl(String request) { 288 | try { 289 | return new URL("https://authserver.mojang.com/" + request); 290 | } catch (Exception e) { 291 | e.printStackTrace(); 292 | return null; 293 | } 294 | } 295 | 296 | private static RequestResponse sendJsonPostRequest(URL requestUrl, String payload, Proxy proxy) throws AuthenticationUnavailableException { 297 | HttpsURLConnection connection = null; 298 | try { 299 | byte[] payloadBytes = payload.getBytes("UTF-8"); 300 | connection = (HttpsURLConnection) (proxy != null ? requestUrl.openConnection(proxy) : requestUrl.openConnection()); 301 | connection.setDoOutput(true); 302 | connection.setDoInput(true); 303 | connection.setInstanceFollowRedirects(false); 304 | connection.setRequestMethod("POST"); 305 | connection.setRequestProperty("Accept-Charset", "UTF-8"); 306 | connection.setRequestProperty("Content-Type", "application/json"); 307 | connection.setRequestProperty("Content-Length", String.valueOf(payloadBytes.length)); 308 | connection.setUseCaches(false); 309 | OutputStream out = connection.getOutputStream(); 310 | out.write(payloadBytes, 0, payloadBytes.length); 311 | out.close(); 312 | 313 | int responseCode = connection.getResponseCode(); 314 | String line; 315 | BufferedReader reader = null; 316 | String response; 317 | switch (responseCode) { 318 | case 200: 319 | reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8")); 320 | response = reader.readLine(); 321 | break; 322 | case 204: 323 | response = ""; 324 | break; 325 | default: 326 | reader = new BufferedReader(new InputStreamReader(connection.getErrorStream(), "UTF-8")); 327 | response = reader.readLine(); 328 | break; 329 | } 330 | if (reader != null) { 331 | reader.close(); 332 | } 333 | Map map = JsonUtils.gson.fromJson(response, JsonUtils.stringObjectMap); 334 | return new RequestResponse(responseCode, map); 335 | } catch (Exception e) { 336 | e.printStackTrace(); 337 | throw new AuthenticationUnavailableException(null); 338 | } finally { 339 | if (connection != null) { 340 | connection.disconnect(); 341 | } 342 | } 343 | } 344 | 345 | } 346 | --------------------------------------------------------------------------------