001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 020package org.apache.oozie.util; 021 022import java.io.BufferedReader; 023import java.io.IOException; 024import java.io.InputStream; 025import java.io.InputStreamReader; 026import java.net.HttpURLConnection; 027import java.net.URL; 028import java.security.PrivilegedExceptionAction; 029import java.util.Map; 030 031import org.apache.hadoop.security.UserGroupInformation; 032import org.apache.hadoop.security.authentication.client.AuthenticatedURL; 033import org.apache.hadoop.security.authentication.client.AuthenticationException; 034import org.apache.hadoop.security.authentication.client.Authenticator; 035import org.apache.hadoop.security.authentication.client.KerberosAuthenticator; 036import org.apache.hadoop.security.authentication.client.PseudoAuthenticator; 037import org.apache.oozie.service.ConfigurationService; 038import org.apache.oozie.service.Services; 039 040public class AuthUrlClient { 041 042 public static final String SERVER_SERVER_AUTH_TYPE = "oozie.server.authentication.type"; 043 044 private static XLog LOG = XLog.getLog(AuthUrlClient.class); 045 046 static private Class<? extends Authenticator> AuthenticatorClass = null; 047 048 static private String errorMsg = null; 049 050 static { 051 try { 052 AuthenticatorClass = determineAuthenticatorClassType(); 053 } 054 catch (Exception e) { 055 errorMsg = e.getMessage(); 056 } 057 } 058 059 private static HttpURLConnection getConnection(URL url) throws IOException { 060 AuthenticatedURL.Token token = new AuthenticatedURL.Token(); 061 HttpURLConnection conn; 062 try { 063 conn = new AuthenticatedURL(AuthenticatorClass.newInstance()).openConnection(url, token); 064 } 065 catch (AuthenticationException ex) { 066 throw new IOException("Could not authenticate, " + ex.getMessage(), ex); 067 } 068 catch (InstantiationException ex) { 069 throw new IOException("Could not authenticate, " + ex.getMessage(), ex); 070 } 071 catch (IllegalAccessException ex) { 072 throw new IOException("Could not authenticate, " + ex.getMessage(), ex); 073 } 074 if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) { 075 throw new IOException("Unexpected response code [" + conn.getResponseCode() + "], message [" 076 + conn.getResponseMessage() + "]"); 077 } 078 return conn; 079 } 080 081 @SuppressWarnings("unchecked") 082 private static Class<? extends Authenticator> determineAuthenticatorClassType() throws Exception { 083 // Adapted from 084 // org.apache.hadoop.security.authentication.server.AuthenticationFilter#init 085 Class<? extends Authenticator> authClass; 086 String authName = ConfigurationService.get(SERVER_SERVER_AUTH_TYPE); 087 088 LOG.info("Oozie server-server authentication is " + authName); 089 090 String authClassName; 091 if (authName == null) { 092 throw new IOException("Authentication type must be specified: simple|kerberos|<class>"); 093 } 094 authName = authName.trim(); 095 if (authName.equals("simple")) { 096 authClassName = PseudoAuthenticator.class.getName(); 097 } 098 else if (authName.equals("kerberos")) { 099 authClassName = KerberosAuthenticator.class.getName(); 100 } 101 else { 102 authClassName = authName; 103 } 104 105 authClass = (Class<? extends Authenticator>) Thread.currentThread().getContextClassLoader() 106 .loadClass(authClassName); 107 return authClass; 108 } 109 110 /** 111 * Calls other Oozie server over HTTP. 112 * 113 * @param server The URL of the other Oozie server 114 * @return BufferedReader of inputstream. 115 * @throws IOException Signals that an I/O exception has occurred. 116 */ 117 public static BufferedReader callServer(String server) throws IOException { 118 119 if (AuthenticatorClass == null) { 120 throw new IOException(errorMsg); 121 } 122 123 final URL url = new URL(server); 124 BufferedReader reader = null; 125 try { 126 reader = UserGroupInformation.getLoginUser().doAs(new PrivilegedExceptionAction<BufferedReader>() { 127 @Override 128 public BufferedReader run() throws IOException { 129 HttpURLConnection conn = getConnection(url); 130 BufferedReader reader = null; 131 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 132 InputStream is = conn.getInputStream(); 133 reader = new BufferedReader(new InputStreamReader(is)); 134 } 135 return reader; 136 } 137 }); 138 } 139 catch (InterruptedException ie) { 140 throw new IOException(ie); 141 } 142 return reader; 143 } 144 145 public static String getQueryParamString(Map<String, String[]> params) { 146 StringBuilder stringBuilder = new StringBuilder(); 147 if (params == null || params.isEmpty()) { 148 return ""; 149 } 150 for (String key : params.keySet()) { 151 if (!key.isEmpty() && params.get(key).length > 0) { 152 stringBuilder.append("&"); 153 String value = params.get(key)[0]; // We don't support multi value. 154 stringBuilder.append(key); 155 stringBuilder.append("="); 156 stringBuilder.append(value); 157 } 158 } 159 return stringBuilder.toString(); 160 } 161 162}