4848import javax .ws .rs .core .MediaType ;
4949import javax .ws .rs .core .Response ;
5050
51+ import java .io .BufferedReader ;
5152import java .io .File ;
5253import java .io .FileInputStream ;
5354import java .io .FileNotFoundException ;
55+ import java .io .FileReader ;
5456import java .io .IOException ;
5557import java .io .InputStream ;
5658import java .security .KeyManagementException ;
6264import java .security .cert .CertificateException ;
6365import java .util .List ;
6466import java .util .Map ;
67+ import java .util .Optional ;
6568import java .util .Random ;
6669import java .util .Set ;
6770import java .util .concurrent .TimeUnit ;
@@ -83,16 +86,18 @@ public class RangerRESTClient {
8386 public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL = "xasecure.policymgr.clientssl.truststore.credential.file" ;
8487 public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL_ALIAS = "sslTrustStore" ;
8588 public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE_DEFAULT = "jks" ;
86-
8789 public static final String RANGER_SSL_KEYMANAGER_ALGO_TYPE = KeyManagerFactory .getDefaultAlgorithm ();
8890 public static final String RANGER_SSL_TRUSTMANAGER_ALGO_TYPE = TrustManagerFactory .getDefaultAlgorithm ();
8991 public static final String RANGER_SSL_CONTEXT_ALGO_TYPE = "TLSv1.2" ;
9092
93+ public static final String JWT_HEADER_PREFIX = "Bearer " ;
94+
9195 private String mUrl ;
9296 private final String mSslConfigFileName ;
9397 private String mUsername ;
9498 private String mPassword ;
9599 private boolean mIsSSL ;
100+ private String jwt ;
96101 private String mKeyStoreURL ;
97102 private String mKeyStoreAlias ;
98103 private String mKeyStoreFile ;
@@ -108,11 +113,16 @@ public class RangerRESTClient {
108113 private int lastKnownActiveUrlIndex ;
109114
110115 private final List <String > configuredURLs ;
116+ private final String propertyPrefix ;
111117
112118 private volatile Client client ;
113119 private volatile Client cookieAuthClient ;
114120
115121 public RangerRESTClient (String url , String sslConfigFileName , Configuration config ) {
122+ this (url , sslConfigFileName , config , getPropertyPrefix (config ));
123+ }
124+
125+ public RangerRESTClient (String url , String sslConfigFileName , Configuration config , String propertyPrefix ) {
116126 mUrl = url ;
117127 mSslConfigFileName = sslConfigFileName ;
118128 configuredURLs = StringUtil .getURLs (mUrl );
@@ -121,6 +131,7 @@ public RangerRESTClient(String url, String sslConfigFileName, Configuration conf
121131 } else {
122132 setLastKnownActiveUrlIndex ((new Random ()).nextInt (getConfiguredURLs ().size ()));
123133 }
134+ this .propertyPrefix = propertyPrefix ;
124135 init (config );
125136 }
126137
@@ -198,7 +209,7 @@ public Client getClient() {
198209 result = client ;
199210
200211 if (result == null ) {
201- result = buildClient (true );
212+ result = buildClient ();
202213 client = result ;
203214 }
204215 }
@@ -215,7 +226,7 @@ public Client getCookieAuthClient() {
215226 ret = cookieAuthClient ;
216227
217228 if (ret == null ) {
218- cookieAuthClient = buildClient (true );
229+ cookieAuthClient = buildClient ();
219230 //Pending : need to remove basic auth filter from client.
220231 ret = cookieAuthClient ;
221232 }
@@ -225,7 +236,11 @@ public Client getCookieAuthClient() {
225236 return ret ;
226237 }
227238
228- private Client buildClient (boolean isBasicAuth ) {
239+ private static String getPropertyPrefix (Configuration config ) {
240+ return (config instanceof RangerPluginConfig ) ? ((RangerPluginConfig ) config ).getPropertyPrefix () : "ranger.plugin" ;
241+ }
242+
243+ private Client buildClient () {
229244 RangerJersey2ClientBuilder .SafeClientBuilder clientBuilder ;
230245 ClientConfig config = new ClientConfig ();
231246
@@ -263,11 +278,21 @@ public boolean verify(String urlHostName, SSLSession session) {
263278 // Validate that MOXy prevention is properly configured
264279 RangerJersey2ClientBuilder .validateAntiMoxyConfiguration (config );
265280
266- if (isBasicAuth && StringUtils .isNotEmpty (mUsername ) && StringUtils .isNotEmpty (mPassword )) {
281+ final String authHeader ;
282+ if (StringUtils .isNotEmpty (jwt )) { // use JWT if present
283+ authHeader = JWT_HEADER_PREFIX + jwt ;
284+ LOG .info ("Registering JWT auth header in REST client" );
285+ } else if (StringUtils .isNotEmpty (mUsername ) && StringUtils .isNotEmpty (mPassword )) {
286+ authHeader = "Basic " + java .util .Base64 .getEncoder ().encodeToString ((mUsername + ":" + mPassword ).getBytes ());
287+ LOG .info ("Registering Basic auth header in REST client" );
288+ } else {
289+ authHeader = null ;
290+ }
291+
292+ if (StringUtils .isNotEmpty (authHeader )) {
267293 config .register (new javax .ws .rs .client .ClientRequestFilter () {
268294 @ Override
269295 public void filter (javax .ws .rs .client .ClientRequestContext requestContext ) {
270- String authHeader = "Basic " + java .util .Base64 .getEncoder ().encodeToString ((mUsername + ":" + mPassword ).getBytes ());
271296 requestContext .getHeaders ().add ("Authorization" , authHeader );
272297 }
273298 });
@@ -314,16 +339,11 @@ private void init(Configuration config) {
314339 }
315340 }
316341
317- final String pluginPropertyPrefix ;
318-
319- if (config instanceof RangerPluginConfig ) {
320- pluginPropertyPrefix = ((RangerPluginConfig ) config ).getPropertyPrefix ();
321- } else {
322- pluginPropertyPrefix = "ranger.plugin" ;
323- }
342+ Optional <String > jwtAsString = fetchJWT (propertyPrefix , config );
343+ jwtAsString .ifPresent (s -> this .jwt = s );
324344
325- String username = config .get (pluginPropertyPrefix + ".policy.rest.client.username" );
326- String password = config .get (pluginPropertyPrefix + ".policy.rest.client.password" );
345+ String username = config .get (propertyPrefix + ".policy.rest.client.username" );
346+ String password = config .get (propertyPrefix + ".policy.rest.client.password" );
327347
328348 if (StringUtils .isNotBlank (username ) && StringUtils .isNotBlank (password )) {
329349 setBasicAuthInfo (username , password );
@@ -334,6 +354,60 @@ private boolean isSsl(String url) {
334354 return !StringUtils .isEmpty (url ) && url .toLowerCase ().startsWith ("https" );
335355 }
336356
357+ private Optional <String > fetchJWT (String propertyPrefix , Configuration config ) {
358+ Optional <String > ret = Optional .empty ();
359+ String jwtSrc = config .get (propertyPrefix + ".policy.rest.client.jwt.source" );
360+
361+ if (StringUtils .isNotEmpty (jwtSrc )) {
362+ switch (jwtSrc ) {
363+ case "env" : {
364+ String jwtEnvVar = config .get (propertyPrefix + ".policy.rest.client.jwt.env" );
365+ if (StringUtils .isNotEmpty (jwtEnvVar )){
366+ String jwt = System .getenv (jwtEnvVar );
367+ if (StringUtils .isNotBlank (jwt )) {
368+ ret = Optional .of (jwt );
369+ }
370+ }
371+ break ;
372+ }
373+ case "file" : {
374+ String jwtFilePath = config .get (propertyPrefix + ".policy.rest.client.jwt.file" );
375+ if (StringUtils .isNotEmpty (jwtFilePath )){
376+ File jwtFile = new File (jwtFilePath );
377+ if (jwtFile .exists ()) {
378+ try (BufferedReader reader = new BufferedReader (new FileReader (jwtFile ))) {
379+ String line = null ;
380+ while ((line = reader .readLine ()) != null ) {
381+ if (StringUtils .isNotBlank (line ) && !line .startsWith ("#" )) {
382+ ret = Optional .of (line );
383+ break ;
384+ }
385+ }
386+ } catch (IOException e ) {
387+ LOG .error ("Failed to read JWT from file: {}" , jwtFilePath , e );
388+ }
389+ }
390+ }
391+ break ;
392+ }
393+ case "cred" : {
394+ String credFilePath = config .get (propertyPrefix + ".policy.rest.client.jwt.cred.file" );
395+ String credAlias = config .get (propertyPrefix + ".policy.rest.client.jwt.cred.alias" );
396+ if (StringUtils .isNotEmpty (credFilePath ) && StringUtils .isNotEmpty (credAlias )){
397+ String jwt = RangerCredentialProvider .getInstance ().getCredentialString (credFilePath , credAlias );
398+ if (StringUtils .isNotBlank (jwt )) {
399+ ret = Optional .of (jwt );
400+ }
401+ }
402+ break ;
403+ }
404+ }
405+ } else {
406+ LOG .info ("JWT source not configured, proceeding without JWT" );
407+ }
408+ return ret ;
409+ }
410+
337411 private KeyManager [] getKeyManagers () {
338412 KeyManager [] kmList = null ;
339413
0 commit comments