001 // $HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/portal/standard/security/control/LoginListener.java $
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 Department of Geography, University of Bonn
006 and
007 lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036 package org.deegree.portal.standard.security.control;
037
038 import java.io.IOException;
039 import java.io.Reader;
040 import java.io.StringReader;
041 import java.net.URL;
042 import java.net.URLEncoder;
043 import java.nio.charset.Charset;
044
045 import javax.servlet.http.HttpServletRequest;
046 import javax.servlet.http.HttpSession;
047
048 import org.deegree.enterprise.control.AbstractListener;
049 import org.deegree.enterprise.control.FormEvent;
050 import org.deegree.enterprise.control.RPCMethodCall;
051 import org.deegree.enterprise.control.RPCStruct;
052 import org.deegree.enterprise.control.RPCUtils;
053 import org.deegree.enterprise.control.RPCWebEvent;
054 import org.deegree.framework.log.ILogger;
055 import org.deegree.framework.log.LoggerFactory;
056 import org.deegree.framework.util.CharsetUtils;
057 import org.deegree.framework.util.NetWorker;
058 import org.deegree.framework.xml.NamespaceContext;
059 import org.deegree.framework.xml.XMLParsingException;
060 import org.deegree.framework.xml.XMLTools;
061 import org.deegree.i18n.Messages;
062 import org.deegree.ogcbase.BaseURL;
063 import org.deegree.ogcbase.CommonNamespaces;
064 import org.deegree.ogcwebservices.InvalidParameterValueException;
065 import org.deegree.ogcwebservices.OWSUtils;
066 import org.deegree.portal.Constants;
067 import org.deegree.portal.context.GeneralExtension;
068 import org.deegree.portal.context.ViewContext;
069 import org.w3c.dom.Document;
070 import org.xml.sax.SAXException;
071
072 /**
073 * Listener class for handling login to iGeoPortal standard edition
074 *
075 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
076 * @author last edited by: $Author: mschneider $
077 *
078 * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
079 */
080 public class LoginListener extends AbstractListener {
081
082 private static ILogger LOG = LoggerFactory.getLogger( LoginListener.class );
083
084 private static final NamespaceContext nsContext = CommonNamespaces.getNamespaceContext();
085
086 /**
087 * performs a login request. the passed event contains a RPC method call containing user name
088 * and password.
089 *
090 * @see org.deegree.enterprise.control.WebListener#actionPerformed(org.deegree.enterprise.control.FormEvent)
091 *
092 * @param event
093 */
094 @Override
095 public void actionPerformed( FormEvent event ) {
096
097 RPCWebEvent re = (RPCWebEvent) event;
098
099 if ( !validateRequest( re ) ) {
100 gotoErrorPage( Messages.getMessage( "IGEO_STD_SEC_INVALID_LOGIN" ) );
101 LOG.logDebug( Messages.getMessage( "IGEO_STD_SEC_INVALID_LOGIN" ) );
102 return;
103 }
104
105 String[] result = null;
106 try {
107 result = performLogin( re );
108 } catch ( InvalidParameterValueException ipve ) {
109 gotoErrorPage( ipve.toString() );
110 LOG.logDebug( ipve.getMessage(), ipve );
111 return;
112 } catch ( LoginFailureException lfe ) {
113 LOG.logDebug( lfe.getMessage(), lfe );
114 try {
115 handleLoginFailure( lfe.getMessage() );
116 } catch ( Exception e ) {
117 gotoErrorPage( e.toString() );
118 LOG.logDebug( e.getMessage(), e );
119 return;
120 }
121 return;
122 } catch ( Exception e ) {
123 gotoErrorPage( e.toString() );
124 LOG.logDebug( e.getMessage(), e );
125 return;
126 }
127
128 // write request parameter into session to reconstruct the search form
129 HttpSession session = ( (HttpServletRequest) this.getRequest() ).getSession( true );
130 session.setAttribute( "SESSIONID", result[0] );
131 getRequest().setAttribute( "SESSIONID", result[0] );
132 getRequest().setAttribute( "USER", result[1] );
133 }
134
135 /**
136 * handles the case if a login fails. extracts the message from the exception XML and pass it to
137 * the error page (error.jsp)
138 *
139 * @param messageXML
140 * @throws SAXException
141 * @throws XMLParsingException
142 * @throws IOException
143 */
144 private void handleLoginFailure( String messageXML )
145 throws SAXException, XMLParsingException, IOException {
146 Reader reader = new StringReader( messageXML );
147 Document doc = XMLTools.parse( reader );
148 String message = XMLTools.getRequiredNodeAsString( doc.getDocumentElement(),
149 "/ServiceExceptionReport/ServiceException", nsContext );
150 gotoErrorPage( message );
151 }
152
153 /**
154 * validates the passed event to be valid against the requirements of the listener (contains user
155 * name and password)
156 *
157 * @param event
158 * @return true if the request is valide
159 */
160 private boolean validateRequest( RPCWebEvent event ) {
161 RPCMethodCall mc = event.getRPCMethodCall();
162 if ( mc.getParameters().length == 0 ) {
163 return false;
164 }
165 RPCStruct struct = (RPCStruct) mc.getParameters()[0].getValue();
166 if ( struct.getMember( "NAME" ) == null ) {
167 return false;
168 }
169 if ( struct.getMember( "PASSWORD" ) == null ) {
170 return false;
171 }
172 return true;
173 }
174
175 private String getAddress() {
176 HttpSession session = ( (HttpServletRequest) getRequest() ).getSession( true );
177 ViewContext vc = (ViewContext) session.getAttribute( Constants.CURRENTMAPCONTEXT );
178 GeneralExtension ge = vc.getGeneral().getExtension();
179 BaseURL baseUrl = ge.getAuthentificationSettings().getAuthentificationURL();
180 return NetWorker.url2String( baseUrl.getOnlineResource() );
181 }
182
183 /**
184 * peforms a login by requesting a session ID from a WAAS like service (deegree SessionServlet).
185 * The returned session ID is assigned to a session at the WAAS like service to enable vice
186 * versa to identify the user through the ID.
187 *
188 * @param event
189 * @return a string array containing session id [0] and user name [1], if login was successful
190 * @throws InvalidParameterValueException
191 * @throws LoginFailureException
192 * if user/password is not known to the system.
193 * @throws IOException
194 */
195 private String[] performLogin( RPCWebEvent event )
196 throws InvalidParameterValueException, LoginFailureException, IOException {
197 RPCMethodCall mc = event.getRPCMethodCall();
198 RPCStruct struct = (RPCStruct) mc.getParameters()[0].getValue();
199 String name = RPCUtils.getRpcPropertyAsString( struct, "NAME" );
200 String password = RPCUtils.getRpcPropertyAsString( struct, "PASSWORD" );
201 if ( name == null || name.length() == 0 ) {
202 throw new InvalidParameterValueException( Messages.getMessage( "IGEO_STD_SEC_INVALID_USERNAME", name ) );
203 }
204 if ( password == null || password.length() == 0 ) {
205 throw new InvalidParameterValueException( Messages.getMessage( "IGEO_STD_SEC_INVALID_PASSWORD" ) );
206 }
207
208 // create request against WAS
209 StringBuffer sb = new StringBuffer( 500 );
210 String address = OWSUtils.validateHTTPGetBaseURL( getAddress() );
211 sb.append( address );
212 sb.append( "SERVICE=WAS&VERSION=1.0.0&REQUEST=GetSession&" );
213 sb.append( "AUTHMETHOD=urn:x-gdi-nrw:authnMethod:1.0:password&CREDENTIALS=" );
214 sb.append( name ).append( ',' ).append( URLEncoder.encode( password, Charset.defaultCharset().displayName() ) );
215 URL url = new URL( sb.toString() );
216
217 // if the user is not known to the WAS an Exception is thrown at
218 // org.deegree.security.drm.SQLRegistry.getUserByName(SQLRegistry.java)
219 // "Lookup of user 'sadfas' failed! A user with this name does not exist."
220
221 // connect WAS to acquire a session ID
222 NetWorker nw = new NetWorker( CharsetUtils.getSystemCharset(), url );
223 byte[] b = nw.getDataAsByteArr( 50 );
224 String response = new String( b );
225
226 // the byte array and the new String() may contain an xml exception message like this:
227 // <?xml version="1.0" encoding="ISO-8859-1"?>
228 // <ServiceExceptionReport>
229 // <ServiceException locator="-">Lookup of user 'sadfas' failed! A user with this name does
230 // not exist.</ServiceException>
231 // </ServiceExceptionReport>
232
233 if ( response.contains( "ServiceExceptionReport" ) ) {
234 throw new LoginFailureException( response );
235 }
236
237 // return session id and user name if login was successful
238 String[] res = new String[2];
239 res[0] = response;
240 res[1] = name;
241 return res;
242 }
243
244 }