Previously, we’ve featured something about the subject matter: Using the undocumented Rest API: authentication and invocation of Tableau Server
In that post we’ve described the mechanism behind tableau webservice authentication in details. This article is a really close follow up in Java, where we will be using apache HTTPClient and a maven project.
The basic steps are:
- Create an HTTP request to get the modulus and exponent of the servers public RSA key and the authencity_token from “/auth.xml”
- parse the xml to get the corresponding values
- create the RSA public key from the values and encode the user password
- send back the username, encoded user password and authencity_token for the webservice to “/auth/login.xml”
- give back the authenticated HTTPClient to the user
You can download the github maven project which includes dependencies from here, or if you only want to check out the code, here it is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
/** * */ package tableauSrvrWebservice.Auth; /** * @author Horváth Attila * @created 2013.08.02 * */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.StringReader; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.RSAPublicKeySpec; import java.util.ArrayList; import java.util.List; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.codec.binary.Hex; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; public class WebServiceClient { /** * Fetches The httpresp HttpResponse into a StringBuffer * * @param httpresp * HttpResponse * @return StringBuffer with contents of the HttpResponse * @throws IOException */ public static StringBuffer fetchResponse(HttpResponse httpresp) throws IOException { BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(httpresp.getEntity().getContent())); StringBuffer strbuffer = new StringBuffer(); String currentline = ""; while ((currentline = bufferedReader.readLine()) != null) { strbuffer.append(currentline); } return strbuffer; } /** * Creates a HttpClient with authenticated connection to the Tableau Server * * @param serveraddress * - URL address of the Tableau Server * @param user * - Username on Tableau Server * @param password * - Corresponding password to the Username * @return HttpClient with authenticated connection to the Tableau Server * @throws ClientProtocolException * @throws IOException * @throws ParserConfigurationException * @throws SAXException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws IllegalBlockSizeException * @throws BadPaddingException */ public static HttpClient authenticate(String serveraddress, String user, String password) throws ClientProtocolException, IOException, ParserConfigurationException, SAXException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { // Initialize apache HttpClient HttpClient client = new DefaultHttpClient(); // Create Http Get request for authentication informations String url = serveraddress + "/auth.xml"; HttpGet request = new HttpGet(url); HttpResponse response = client.execute(request); StringBuffer result = fetchResponse(response); // Parse XML FROM the result StringReader reader = new StringReader(result.toString()); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); InputSource is = new InputSource(); is.setCharacterStream(reader); Document doc = db.parse(is); // Get Required data for creating the authentication request, such as // modulus and exponent of the RSA public key and the authencity_token String modulusstr = null; String exponentstr = null; String authencity_token = null; NodeList elements = doc.getElementsByTagName("authinfo"); for (int i = 0; i < elements.getLength(); i++) { NodeList moduluses = ((Element) elements.item(i)) .getElementsByTagName("modulus"); for (int k = 0; k < moduluses.getLength(); k++) { modulusstr = moduluses.item(k).getTextContent(); } NodeList exponents = ((Element) elements.item(i)) .getElementsByTagName("exponent"); for (int k = 0; k < exponents.getLength(); k++) { exponentstr = exponents.item(k).getTextContent(); } NodeList authencity_tokens = ((Element) elements.item(i)) .getElementsByTagName("authenticity_token"); for (int k = 0; k < exponents.getLength(); k++) { authencity_token = authencity_tokens.item(k).getTextContent(); } } // Parse the modulus and exponent into a BigInteger and create an RSA // public key from it BigInteger modulus = new BigInteger(modulusstr, 16); BigInteger exponent = new BigInteger(exponentstr, 16); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPublicKeySpec pub = new RSAPublicKeySpec(modulus, exponent); PublicKey pubkey = keyFactory.generatePublic(pub); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pubkey); // Encrypt the password with the created public key byte[] cipherData = cipher.doFinal(password.getBytes()); String cryptedpass = Hex.encodeHexString(cipherData); // Create a post request for the authentication HttpPost postrequest = new HttpPost(serveraddress + "/auth/login.xml"); // Fill in parameters List<NameValuePair> nvps = new ArrayList<NameValuePair>(); nvps.add(new BasicNameValuePair("authenticity_token", authencity_token)); nvps.add(new BasicNameValuePair("crypted", cryptedpass)); nvps.add(new BasicNameValuePair("username", user)); // bind parameters to the request postrequest.setEntity(new UrlEncodedFormEntity(nvps)); HttpResponse postResponse = client.execute(postrequest); // We clear the entity here so we don't have to shutdown the client fetchResponse(postResponse); return client; } } |
Looking for the REST API method? Click here.
Latest posts by Tamás Földi (see all)
- Tableau Extensions Addons Introduction: Synchronized Scrollbars - December 2, 2019
- Tableau External Services API: Adding Haskell Expressions as Calculations - November 20, 2019
- Scaling out Tableau Extracts – Building a distributed, multi-node MPP Hyper Cluster - August 11, 2019