001/** 002 * Copyright (C) 2006-2020 Talend Inc. - www.talend.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.talend.sdk.component.server.service.httpurlconnection; 017 018import java.lang.reflect.InvocationTargetException; 019import java.lang.reflect.Method; 020import java.lang.reflect.Modifier; 021import java.net.Authenticator; 022import java.net.PasswordAuthentication; 023import java.net.URL; 024import java.util.stream.Stream; 025 026import javax.annotation.PostConstruct; 027import javax.annotation.PreDestroy; 028import javax.enterprise.context.ApplicationScoped; 029import javax.inject.Inject; 030 031@ApplicationScoped 032public class NetAuthenticatorWorkaround { 033 034 @Inject 035 private NetAuthenticatorController controller; 036 037 private volatile Authenticator original; 038 039 @PostConstruct 040 private void init() { 041 original = getAuthenticator(); 042 Authenticator.setDefault(new ApplicationAuthenticator(original, controller)); 043 } 044 045 public void lazyInit() { 046 // no-op 047 } 048 049 @PreDestroy 050 private void destroy() { 051 Authenticator.setDefault(original); 052 } 053 054 private Authenticator getAuthenticator() { 055 return Stream 056 .of(Authenticator.class.getDeclaredFields()) 057 .filter(f -> Modifier.isStatic(f.getModifiers()) && Modifier.isPrivate(f.getModifiers()) 058 && f.getType() == Authenticator.class) 059 .findFirst() 060 .map(f -> { 061 if (!f.isAccessible()) { 062 f.setAccessible(true); 063 } 064 try { 065 return Authenticator.class.cast(f.get(null)); 066 } catch (final IllegalAccessException e) { 067 throw new IllegalStateException(e); 068 } 069 }) 070 .orElse(null); 071 } 072 073 private static class ApplicationAuthenticator extends Authenticator { 074 075 private final Authenticator delegate; 076 077 private final NetAuthenticatorController controller; 078 079 private final Method getRequestorType; 080 081 private final Method getPasswordAuthentication; 082 083 private final Method getRequestingURL; 084 085 private ApplicationAuthenticator(final Authenticator original, final NetAuthenticatorController controller) { 086 this.getPasswordAuthentication = findMethod("getPasswordAuthentication"); 087 this.getRequestingURL = findMethod("getRequestingURL"); 088 this.getRequestorType = findMethod("getRequestorType"); 089 this.delegate = original; 090 this.controller = controller; 091 } 092 093 private Method findMethod(final String name) { 094 final Method declaredMethod; 095 try { 096 declaredMethod = Authenticator.class.getDeclaredMethod(name); 097 } catch (final NoSuchMethodException e) { 098 throw new IllegalStateException(e); 099 } 100 if (!declaredMethod.isAccessible()) { 101 declaredMethod.setAccessible(true); 102 } 103 return declaredMethod; 104 } 105 106 private boolean shouldSkip() { 107 return delegate == null || controller.isSkipped(); 108 } 109 110 @Override 111 public PasswordAuthentication getPasswordAuthentication() { 112 try { 113 return shouldSkip() ? null 114 : PasswordAuthentication.class.cast(getPasswordAuthentication.invoke(delegate)); 115 } catch (final IllegalAccessException e) { 116 throw new IllegalStateException(e); 117 } catch (final InvocationTargetException e) { 118 throw new IllegalStateException(e.getTargetException()); 119 } 120 } 121 122 @Override 123 public URL getRequestingURL() { 124 try { 125 return shouldSkip() ? null : URL.class.cast(getRequestingURL.invoke(delegate)); 126 } catch (final IllegalAccessException e) { 127 throw new IllegalStateException(e); 128 } catch (final InvocationTargetException e) { 129 throw new IllegalStateException(e.getTargetException()); 130 } 131 } 132 133 @Override 134 public RequestorType getRequestorType() { 135 try { 136 return shouldSkip() ? null : RequestorType.class.cast(getRequestorType.invoke(delegate)); 137 } catch (final IllegalAccessException e) { 138 throw new IllegalStateException(e); 139 } catch (final InvocationTargetException e) { 140 throw new IllegalStateException(e.getTargetException()); 141 } 142 } 143 } 144}