001/* 002 * JKNIV, whinstone one contract to access your database. 003 * 004 * Copyright (C) 2017, the original author or authors. 005 * 006 * This library is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 2.1 of the License. 010 * 011 * This library is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with this library; if not, write to the Free Software Foundation, Inc., 018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 019 */ 020package net.sf.jkniv.whinstone.couchdb; 021 022import java.io.IOException; 023import java.io.UnsupportedEncodingException; 024import java.net.URI; 025import java.net.URISyntaxException; 026import java.nio.charset.Charset; 027import java.util.Date; 028import java.util.concurrent.TimeUnit; 029 030import org.apache.http.Consts; 031import org.apache.http.Header; 032import org.apache.http.HeaderIterator; 033import org.apache.http.client.ClientProtocolException; 034import org.apache.http.client.methods.CloseableHttpResponse; 035import org.apache.http.client.methods.HttpPost; 036import org.apache.http.client.utils.URIBuilder; 037import org.apache.http.entity.StringEntity; 038import org.apache.http.impl.client.CloseableHttpClient; 039import org.apache.http.impl.client.HttpClients; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042 043import net.sf.jkniv.exception.HandlerException; 044import net.sf.jkniv.sqlegance.RepositoryException; 045 046public class CouchDbAuthenticate 047{ 048 private static final Logger LOG = LoggerFactory.getLogger(CouchDbAuthenticate.class); 049 private static final String AUTH_COOKIE = "Set-Cookie"; 050 private final HandlerException handlerException; 051 private Date startSession; 052 private long sessionTimeout; 053 private String url; 054 private String username; 055 private String password; 056 private String cookieSession; 057 058 /** 059 * Build a new Authentication with 10 minutes to expire after authenticate. 060 * @param url Uniform Resource Locator pointing to CouchDb instance 061 * @param username couchDb user name 062 * @param password couchDb password 063 */ 064 public CouchDbAuthenticate(String url, String username, String password) 065 { 066 super(); 067 this.url = url; 068 this.username = username; 069 this.password = password; 070 this.sessionTimeout = TimeUnit.MINUTES.toMillis(10L); 071 this.handlerException = new HandlerException(RepositoryException.class, "Cannot connect to couchdb [%s]"); 072 configHanlerException(); 073 } 074 075 private void configHanlerException() 076 { 077 // ClientProtocolException | URISyntaxException | UnsupportedEncodingException | IOException 078 handlerException.config(ClientProtocolException.class, "Error at HTTP protocol [%s]"); 079 handlerException.config(URISyntaxException.class, "Error to parser URI [%s]"); 080 handlerException.config(UnsupportedEncodingException.class, "Character encoding unsupported"); 081 handlerException.config(IOException.class, "Error from I/O json content [%s]"); 082 } 083 084 /** 085 * Retrieve the cookie session for user authenticated 086 * @return cookie session number for this user authenticated, default session time it's for 10 minutes 087 */ 088 public String authenticate() 089 { 090 String token = ""; 091 CloseableHttpResponse response = null; 092 try 093 { 094 URIBuilder uri = new URIBuilder(new URI(url)).setCharset(Charset.defaultCharset()).setPath("_session"); 095 CloseableHttpClient httpclient = HttpClients.createDefault(); 096 097 HttpPost httpPost = new HttpPost(uri.build()); 098 httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); 099 StringEntity xmlEntity = new StringEntity("name=" + username + "&password=" + password, Consts.UTF_8); // TODO config charset for HTTP body 100 httpPost.setEntity(xmlEntity); 101 102 response = httpclient.execute(httpPost); 103 LOG.debug(response.getStatusLine().toString()); 104 int statusCode = response.getStatusLine().getStatusCode(); 105 if (statusCode == 200) 106 { 107 this.startSession = new Date(); 108 HeaderIterator it = response.headerIterator(); 109 while (it.hasNext()) 110 { 111 Header header = it.nextHeader(); 112 if (AUTH_COOKIE.equals(header.getName())) 113 { 114 token = header.getValue().split(";")[0]; 115 this.cookieSession = token; 116 } 117 } 118 } 119 else if (statusCode == 401) 120 { 121 throw new RepositoryException("Access denied, unauthorized for user ["+username+"] and url ["+url+"]"); 122 } 123 else 124 throw new RepositoryException( 125 "Http code[" + statusCode + "] " + response.getStatusLine().getReasonPhrase()); 126 } 127 // ClientProtocolException | URISyntaxException | UnsupportedEncodingException | IOException 128 catch (Exception ex) 129 { 130 this.handlerException.handle(ex, url); 131 } 132 finally 133 { 134 if (response != null) 135 { 136 try 137 { 138 response.close(); 139 } 140 catch (IOException e) 141 { 142 this.handlerException.handle(e, url); 143 } 144 } 145 } 146 return token; 147 } 148 149 public String getCookieSession() 150 { 151 return cookieSession; 152 } 153 154 public boolean isExpired() 155 { 156 if (this.startSession == null) 157 return true; 158 159 return (new Date().getTime() > (this.startSession.getTime()+sessionTimeout)); 160 } 161 162 public void keepAlive() 163 { 164 this.startSession = new Date(); 165 } 166}