private void setupAuthUrl(Mapping mapping) { authMapping = mapping; Authorizer authorizer = config.getAuthorizer(); String selfDomain = config.getString("selfDomain"); String realHostName = mapping.getRealHostName(); RealHost realHost = RealHost.getRealHost(realHostName); if (realHost == null) { logger.warn("not found auth mapping realHost.realHostName:" + realHostName); return; } authorizer.setupAuthUrl( (mapping.getSecureType() == SecureType.SSL), mapping.getSourcePath(), selfDomain, realHost.getBindPort()); }
public long getInjectLength() { if (injectContext != null) { InjectionHelper helper = config.getInjectionHelper(); return helper.getInjectContentsLength(injectContext); } return 0; }
private synchronized void addWsClient() { if (stat != Stat.INC) { return; } int size = clients.size(); if ((size % 100) == 0 || size == count) { publish(size, failCount, false); } if (size >= count) { if (timerId == TimerManager.INVALID_ID) { stop(); } else { stat = Stat.KEEP; } return; } WsClientHandler wsClientHandler = WsClientHandler.create(false, config.getSelfDomain(), config.getInt(Config.SELF_PORT)); wsClientHandler.ref(); wsClientHandler.startRequest( this, wsClientHandler, 10000, "/connect", "connect", config.getAdminUrl()); clients.add(wsClientHandler); }
public void startResponseReqBody() { MappingResult mapping = getRequestMapping(); if (Boolean.TRUE.equals(mapping.getOption("replay"))) { ReplayHelper helper = Config.getConfig().getReplayHelper(); // ByteBuffer[] body=bodyPage.getBuffer(); if (helper.doReplay(this, null)) { return; // replayできた,bodyは消費されている } } if (response()) { responseEnd(); // TODO必要ないと思う return; } }
// 存在確認済みのディレクトリを一覧レスポンスする。 private boolean snedFileList(MappingResult mapping, String uri, File dir, boolean isBase) { if (!uri.endsWith("/")) { uri = uri + "/"; } setRequestAttribute("isBase", isBase); setRequestAttribute("base", uri); try { setRequestAttribute("source", dir.getCanonicalFile()); } catch (IOException e) { setRequestAttribute("source", null); } setRequestAttribute("fileList", dir.listFiles()); setRequestAttribute(ATTRIBUTE_VELOCITY_ENGINE, config.getVelocityEngine()); setRequestAttribute(ATTRIBUTE_VELOCITY_TEMPLATE, LISTING_TEMPLATE); forwardHandler(Mapping.VELOCITY_PAGE_HANDLER); return false; // 委譲 }
/* 自サーバの/connection WebScoketに接続する */ public class ConnectChecker implements Timer, WsClient { private static Logger logger = Logger.getLogger(ConnectChecker.class); private static Config config = Config.getConfig(); private static ConnectChecker instance = new ConnectChecker(); private enum Stat { READY, STARTING, INC, // connection増加中 KEEP, // 保持中 DEC, // connection切断中 } private List<WsClientHandler> clients = new ArrayList<WsClientHandler>(); private int failCount; private PaPeer peer; private int count; private int maxFailCount; private Stat stat = Stat.READY; private long timerId; private long startTime; public static boolean start(int count, int maxFailCount, long timeout, PaPeer peer) { if (instance.init(count, maxFailCount, peer) == false) { return false; } instance.run(timeout); return true; } public static void end() { instance.stop(); } private synchronized boolean init(int count, int maxFailCount, PaPeer peer) { if (stat != Stat.READY) { logger.error("aleady start." + stat); // queueManager.complete(chId, null); return false; } if (this.peer != null) { this.peer.unref(); } if (peer != null) { peer.ref(); } this.peer = peer; this.count = count; this.maxFailCount = maxFailCount; this.failCount = 0; // this.paManager=config.getAdminPaManager(); if (count > 0) { stat = Stat.INC; } else { stat = Stat.KEEP; } return true; } private static Runtime runtime = Runtime.getRuntime(); private void publish(int count, int failCount, boolean isComplete) { JSONObject eventObj = new JSONObject(); eventObj.put("kind", "checkConnectProgress"); eventObj.put("time", (System.currentTimeMillis() - startTime)); eventObj.put("connectCount", count); eventObj.put("failCount", failCount); eventObj.put("useMemory", (runtime.totalMemory() - runtime.freeMemory())); eventObj.put("stat", stat); peer.message(eventObj); if (isComplete) { peer.unref(); peer = null; } } private synchronized void addWsClient() { if (stat != Stat.INC) { return; } int size = clients.size(); if ((size % 100) == 0 || size == count) { publish(size, failCount, false); } if (size >= count) { if (timerId == TimerManager.INVALID_ID) { stop(); } else { stat = Stat.KEEP; } return; } WsClientHandler wsClientHandler = WsClientHandler.create(false, config.getSelfDomain(), config.getInt(Config.SELF_PORT)); wsClientHandler.ref(); wsClientHandler.startRequest( this, wsClientHandler, 10000, "/connect", "connect", config.getAdminUrl()); clients.add(wsClientHandler); } private synchronized void delWsClient(WsClientHandler wsClientHandler, boolean isFail) { clients.remove(wsClientHandler); wsClientHandler.unref(); int size = clients.size(); if (isFail) { failCount++; if (failCount >= maxFailCount) { publish(size, failCount, false); stop(); return; } } switch (stat) { case INC: addWsClient(); break; case DEC: if ((size % 100) == 0) { publish(size, failCount, false); } sendStop(); break; } } private void sendStop() { Iterator<WsClientHandler> itr = clients.iterator(); if (itr.hasNext()) { WsClientHandler client = itr.next(); client.postMessage("doClose"); } else { // clientsが空 stat = Stat.READY; publish(0, failCount, true); } } private void run(long timeout) { startTime = System.currentTimeMillis(); if (timeout > 0) { timerId = TimerManager.setTimeout(timeout, this, null); } else { timerId = TimerManager.INVALID_ID; } addWsClient(); } private synchronized void stop() { if (stat == Stat.DEC || stat == Stat.READY) { logger.warn("aleady stoped"); return; } stat = Stat.DEC; sendStop(); } /* public void postAll(){ String now=Long.toString(System.currentTimeMillis()); synchronized(this){ if(isStop){ logger.warn("ConnectChecker was stoped"); return; } isStop=true; for(WsClientHandler client:clients){ client.postMessage(now); } } } */ public void onTimer(Object userContext) { timerId = TimerManager.INVALID_ID; int curCount; synchronized (this) { curCount = clients.size(); } publish(curCount, failCount, false); stop(); } @Override public void onWcClose(Object userContext, int stat, short closeCode, String closeReason) { WsClientHandler wsClientHandler = (WsClientHandler) userContext; delWsClient(wsClientHandler, false); } @Override public void onWcConnected(Object userContext) {} @Override public void onWcFailure(Object userContext, int stat, Throwable t) { logger.info("#wcFailure", t); WsClientHandler wsClientHandler = (WsClientHandler) userContext; delWsClient(wsClientHandler, true); } @Override public void onWcHandshaked(Object userContext, String subprotocol) {} @Override public void onWcMessage(Object userContext, String message) { if ("OK".equals(message)) { addWsClient(); return; } long sendTime = Long.parseLong(message); long now = System.currentTimeMillis(); } @Override public void onWcMessage(Object userContext, CacheBuffer message) {} @Override public void onWcProxyConnected(Object userContext) {} @Override public void onWcResponseHeader(Object userContext, HeaderParser responseHeader) {} @Override public void onWcSslHandshaked(Object userContext) {} @Override public void onWcWrittenHeader(Object userContext) {} }
private static Config getConfig() { if (config == null) { config = Config.getConfig(); } return config; }
private void loadMapping(Mapping mapping) { entryMappings.add(mapping); if (!mapping.isEnabled()) { return; } if (Boolean.FALSE.equals(mapping.getOption(OPTION_PEEK))) { synchronized (activeSslProxyMappings) { // ssl proxyは特殊なため別管理 activeSslProxyMappings.add(mapping); } } else { synchronized (activeMappings) { activeMappings.add(mapping); } } String selfDomain = config.getSelfDomain(); RealHost realHost = RealHost.getRealHost(mapping.getRealHostName()); if (Boolean.TRUE.equals(mapping.getOption(OPTION_ADMIN_HANDLER))) { StringBuilder sb = new StringBuilder(); String sourceServer = mapping.getSourceServer(); if (sourceServer == null || "".equals(sourceServer)) { sourceServer = selfDomain; } if (mapping.getSecureType() == SecureType.SSL) { sb.append("https://"); } else { sb.append("http://"); } sb.append(sourceServer); sb.append(":"); sb.append(realHost.getBindPort()); sb.append(mapping.getSourcePath()); adminUrl = sb.toString(); System.out.println("adminUrl:" + adminUrl); } Object publicWeb = mapping.getOption(OPTION_PUBLIC_WEB); // publicWebのportとプロトコルを知るため if (Boolean.TRUE.equals(publicWeb)) { StringBuilder sb = new StringBuilder(); String sourceServer = mapping.getSourceServer(); if (sourceServer == null || "".equals(sourceServer)) { sourceServer = selfDomain; } if (mapping.getSecureType() == SecureType.SSL) { sb.append("https://"); } else { sb.append("http://"); } sb.append(sourceServer); sb.append(":"); sb.append(realHost.getBindPort()); sb.append(mapping.getSourcePath()); publicWebUrl = sb.toString(); } // pacは複数のmappingにあってよいが、そのrealHostは同一である事 // Object authHandler=mapping.getOption(OPTION_AUTH_HANDLER); if (AuthHandler.class.getName().equals(mapping.getDestinationServer())) { setupAuthUrl(mapping); // authorizerにauthマッピング定義を教える } // mapping auth定義 Object auth = mapping.getOption(OPTION_AUTH); if (auth != null && auth instanceof JSONObject) { MappingAuth mappingAuth = new MappingAuth(config.getAuthenticator()); if (mappingAuth.init((JSONObject) auth, mapping.getSourceType() == SourceType.PROXY)) { mapping.setMappingAuth(mappingAuth); } } Object pac = mapping.getOption(OPTION_PAC); // pacに反映するか否か if (!Boolean.TRUE.equals(pac)) { return; } switch (mapping.getSourceType()) { case PROXY: switch (mapping.getSecureType()) { case PLAIN: httpPhantomDomains.add(mapping.getSourceServerHost()); pacProxyPort = realHost.getBindPort(); break; case SSL: securePhantomDomains.add(mapping.getSourceServerHost()); pacProxyPort = realHost.getBindPort(); break; } break; case WEB: } }
public void onResponseHeader(HeaderParser responseHeader) { InjectionHelper helper = config.getInjectionHelper(); MappingResult mapping = proxyHandler.getRequestMapping(); HeaderParser requestHeader = proxyHandler.getRequestHeader(); String WebAuthReplaceMark = requestHeader.getHeader(REPLACE_MARK_HEADER); String resolveUrl = mapping.getResolveUrl(); if (WebAuthReplaceMark == null) { portalSession.endBasicProcess(resolveUrl); } String statusCode = responseHeader.getStatusCode(); if ("401".equals(statusCode) /*&&injectContext==null*/) { mapping.getResolveDomain(); String authentication = responseHeader.getHeader(HeaderParser.WWW_AUTHENTICATE_HEADER); if (authentication == null) { return; } Matcher matcher; synchronized (authenticationPattern) { matcher = authenticationPattern.matcher(authentication); } if (!matcher.find()) { return; // Digestはここでチェックあうと } String realm = matcher.group(1); // 自分の持っている代理ログイン情報で、domain,realmに合致するものはないか? String resolveDomain = mapping.getResolveDomain(); CommissionAuth basicCommissionAuth = portalSession.getBasicAuth(resolveDomain, realm); if (WebAuthReplaceMark == null && !portalSession.startBasicProcess(resolveUrl, basicCommissionAuth)) { return; } if (basicCommissionAuth == null || basicCommissionAuth.isEnabled()) { String authrization = requestHeader.getHeader(HeaderParser.WWW_AUTHORIZATION_HEADER); if (WebAuthReplaceMark == null) { // ブラウザから直接出されたリクエスト responseHeader.setStatusCode("200"); proxyHandler.removeResponseHeader(HeaderParser.WWW_AUTHENTICATE_HEADER); portalSession.putRealm(resolveUrl, realm); proxyHandler.setReplace(true); injectContext = helper.getReplaceContext("WebAuthReplace.html"); proxyHandler.addResponseHeader( HeaderParser.CONTENT_TYPE_HEADER, "text/html; charset=utf-8"); proxyHandler.addResponseHeader("Pragma", "no-cache"); proxyHandler.addResponseHeader("Cache-Control", "no-cache"); proxyHandler.addResponseHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT"); } else if (authrization != null) { // ajaxからuser/passをつけているのに401が返却された=>認証情報が無効 responseHeader.setStatusCode("200"); proxyHandler.removeResponseHeader(HeaderParser.WWW_AUTHENTICATE_HEADER); proxyHandler.addResponseHeader("WebAuthRealm", realm); proxyHandler.setReplace(true); injectContext = helper.getReplaceContext("WebAuthFail.html"); proxyHandler.addResponseHeader(HeaderParser.CONTENT_TYPE_HEADER, "text/plain"); proxyHandler.addResponseHeader("Pragma", "no-cache"); proxyHandler.addResponseHeader("Cache-Control", "no-cache"); proxyHandler.addResponseHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT"); } } } else if ("200".equals(statusCode) || "404".equals(statusCode)) { String contentType = responseHeader.getContentType(); if (contentType != null && contentType.startsWith("text/html")) { injectContext = helper.getInsertContext("PortalInject.txt"); } } }
public class PortalInjector extends PoolBase implements ProxyInjector { private static Pattern portalPathInfoPattern = Pattern.compile(";phportal=([^\\s;/?]*)"); public static final String PORTAL_PATHINFO_KEY = "portalPathInfo"; public static final String REPLACE_MARK_HEADER = "X-PH-WebAuthReplaceMark"; private static Config config = Config.getConfig(); private ProxyHandler proxyHandler; private PortalSession portalSession; private Object injectContext = null; public void init(ProxyHandler proxyHandler) { this.proxyHandler = proxyHandler; this.portalSession = PortalSession.getPortalSession(proxyHandler); injectContext = null; } public void onRequestHeader(HeaderParser requestHeader) { /* portal機能の場合path情報にportal機能用の情報が着いている場合がある。 * この情報は削除してproxy対象サーバにリクエスト */ MappingResult mapping = proxyHandler.getRequestMapping(); String path = mapping.getResolvePath(); Matcher matcher = null; synchronized (portalPathInfoPattern) { matcher = portalPathInfoPattern.matcher(path); } StringBuffer sb = null; String portalPathInfo = null; if (matcher.find()) { sb = new StringBuffer(); matcher.appendReplacement(sb, ""); portalPathInfo = matcher.group(1); matcher.appendTail(sb); path = sb.toString(); mapping.setResolvePath(path); requestHeader.setRequestUri(mapping.getResolvePath()); proxyHandler.setRequestAttribute(PORTAL_PATHINFO_KEY, portalPathInfo); } /* * proxyでAuthrizationヘッダを付加する作戦の場合 String basicAuthHeader = getBasicAuthHeader(mapping.isResolvedHttps(),mapping.getResolveServer()); if (basicAuthHeader != null) { requestHeader.addHeader(HeaderParser.WWW_AUTHRIZATION_HEADER, basicAuthHeader); proxyHandler.setRequestAttribute(HeaderParser.WWW_AUTHRIZATION_HEADER, basicAuthHeader); } */ } private static Pattern authenticationPattern = Pattern.compile("\\s*Basic\\s+realm\\s*=\\s*\"(.[^\"]*)\"", Pattern.CASE_INSENSITIVE); public void onResponseHeader(HeaderParser responseHeader) { InjectionHelper helper = config.getInjectionHelper(); MappingResult mapping = proxyHandler.getRequestMapping(); HeaderParser requestHeader = proxyHandler.getRequestHeader(); String WebAuthReplaceMark = requestHeader.getHeader(REPLACE_MARK_HEADER); String resolveUrl = mapping.getResolveUrl(); if (WebAuthReplaceMark == null) { portalSession.endBasicProcess(resolveUrl); } String statusCode = responseHeader.getStatusCode(); if ("401".equals(statusCode) /*&&injectContext==null*/) { mapping.getResolveDomain(); String authentication = responseHeader.getHeader(HeaderParser.WWW_AUTHENTICATE_HEADER); if (authentication == null) { return; } Matcher matcher; synchronized (authenticationPattern) { matcher = authenticationPattern.matcher(authentication); } if (!matcher.find()) { return; // Digestはここでチェックあうと } String realm = matcher.group(1); // 自分の持っている代理ログイン情報で、domain,realmに合致するものはないか? String resolveDomain = mapping.getResolveDomain(); CommissionAuth basicCommissionAuth = portalSession.getBasicAuth(resolveDomain, realm); if (WebAuthReplaceMark == null && !portalSession.startBasicProcess(resolveUrl, basicCommissionAuth)) { return; } if (basicCommissionAuth == null || basicCommissionAuth.isEnabled()) { String authrization = requestHeader.getHeader(HeaderParser.WWW_AUTHORIZATION_HEADER); if (WebAuthReplaceMark == null) { // ブラウザから直接出されたリクエスト responseHeader.setStatusCode("200"); proxyHandler.removeResponseHeader(HeaderParser.WWW_AUTHENTICATE_HEADER); portalSession.putRealm(resolveUrl, realm); proxyHandler.setReplace(true); injectContext = helper.getReplaceContext("WebAuthReplace.html"); proxyHandler.addResponseHeader( HeaderParser.CONTENT_TYPE_HEADER, "text/html; charset=utf-8"); proxyHandler.addResponseHeader("Pragma", "no-cache"); proxyHandler.addResponseHeader("Cache-Control", "no-cache"); proxyHandler.addResponseHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT"); } else if (authrization != null) { // ajaxからuser/passをつけているのに401が返却された=>認証情報が無効 responseHeader.setStatusCode("200"); proxyHandler.removeResponseHeader(HeaderParser.WWW_AUTHENTICATE_HEADER); proxyHandler.addResponseHeader("WebAuthRealm", realm); proxyHandler.setReplace(true); injectContext = helper.getReplaceContext("WebAuthFail.html"); proxyHandler.addResponseHeader(HeaderParser.CONTENT_TYPE_HEADER, "text/plain"); proxyHandler.addResponseHeader("Pragma", "no-cache"); proxyHandler.addResponseHeader("Cache-Control", "no-cache"); proxyHandler.addResponseHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT"); } } } else if ("200".equals(statusCode) || "404".equals(statusCode)) { String contentType = responseHeader.getContentType(); if (contentType != null && contentType.startsWith("text/html")) { injectContext = helper.getInsertContext("PortalInject.txt"); } } } public ByteBuffer[] onResponseBody(ByteBuffer[] body) { InjectionHelper helper = config.getInjectionHelper(); return helper.inject(injectContext, body); } public void term() { unref(); } public long getInjectLength() { if (injectContext != null) { InjectionHelper helper = config.getInjectionHelper(); return helper.getInjectContentsLength(injectContext); } return 0; } public boolean isInject() { return (injectContext != null); } }
public ByteBuffer[] onResponseBody(ByteBuffer[] body) { InjectionHelper helper = config.getInjectionHelper(); return helper.inject(injectContext, body); }