View Javadoc
1   /**
2    * Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the
3    * COPYRIGHT.txt in the distribution for a full listing of individual contributors.
4    * 
5    * This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
6    * General Public License as published by the Free Software Foundation; either version 3.0 of the
7    * License, or (at your option) any later version.
8    * 
9    * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10   * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11   * GNU Lesser General Public License for more details.
12   * 
13   * You should have received a copy of the GNU Lesser General Public License along with this
14   * software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
15   * Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org.
16   */
17  package org.waarp.gateway.ftp.file;
18  
19  import java.io.File;
20  
21  import org.waarp.common.command.NextCommandReply;
22  import org.waarp.common.command.ReplyCode;
23  import org.waarp.common.command.exception.Reply421Exception;
24  import org.waarp.common.command.exception.Reply530Exception;
25  import org.waarp.common.logging.WaarpLogger;
26  import org.waarp.common.logging.WaarpLoggerFactory;
27  import org.waarp.ftp.core.command.FtpCommandCode;
28  import org.waarp.ftp.core.file.FtpDir;
29  import org.waarp.ftp.core.session.FtpSession;
30  import org.waarp.ftp.filesystembased.FilesystemBasedFtpAuth;
31  import org.waarp.ftp.filesystembased.FilesystemBasedFtpRestart;
32  import org.waarp.gateway.ftp.config.FileBasedConfiguration;
33  import org.waarp.gateway.ftp.database.DbConstant;
34  import org.waarp.gateway.kernel.exec.AbstractExecutor.CommandExecutor;
35  import org.waarp.gateway.kernel.session.HttpAuthInterface;
36  
37  /**
38   * FtpAuth implementation based on a list of (user/password/account) stored in a xml file load at
39   * startup from configuration.
40   * 
41   * @author Frederic Bregier
42   * 
43   */
44  public class FileBasedAuth extends FilesystemBasedFtpAuth implements HttpAuthInterface {
45      /**
46       * Internal Logger
47       */
48      private static final WaarpLogger logger = WaarpLoggerFactory
49              .getLogger(FileBasedAuth.class);
50  
51      /**
52       * Current authentication
53       */
54      private SimpleAuth currentAuth = null;
55  
56      /**
57       * Special Id for the current transfer
58       */
59      private long specialId = DbConstant.ILLEGALVALUE;
60  
61      /**
62       * @param session
63       */
64      public FileBasedAuth(FtpSession session) {
65          super(session);
66      }
67  
68      @Override
69      protected void businessClean() {
70          currentAuth = null;
71      }
72  
73      /**
74       * @param user
75       *            the user to set
76       * @return (NOOP,230) if the user is OK, else return the following command that must follow
77       *         (usually PASS) and the associated reply
78       * @throws Reply421Exception
79       *             if there is a problem during the authentication
80       * @throws Reply530Exception
81       *             if there is a problem during the authentication
82       */
83      @Override
84      protected NextCommandReply setBusinessUser(String user)
85              throws Reply421Exception, Reply530Exception {
86          SimpleAuth auth = ((FileBasedConfiguration) ((FtpSession) getSession())
87                  .getConfiguration()).getSimpleAuth(user);
88          if (auth == null) {
89              setIsIdentified(false);
90              currentAuth = null;
91              throw new Reply530Exception("User name not allowed");
92          }
93          currentAuth = auth;
94          // logger.debug("User: {}", user);
95          return new NextCommandReply(FtpCommandCode.PASS,
96                  ReplyCode.REPLY_331_USER_NAME_OKAY_NEED_PASSWORD, null);
97      }
98  
99      /**
100      * Set the password according to any implementation and could set the rootFromAuth. If NOOP is
101      * returned, isIdentifed must be TRUE. A special case is implemented for test user.
102      * 
103      * @param password
104      * @return (NOOP,230) if the Password is OK, else return the following command that must follow
105      *         (usually ACCT) and the associated reply
106      * @throws Reply421Exception
107      *             if there is a problem during the authentication
108      * @throws Reply530Exception
109      *             if there is a problem during the authentication
110      */
111     @Override
112     protected NextCommandReply setBusinessPassword(String password)
113             throws Reply421Exception, Reply530Exception {
114         if (currentAuth == null) {
115             setIsIdentified(false);
116             throw new Reply530Exception("PASS needs a USER first");
117         }
118         if (currentAuth.isPasswordValid(password)) {
119             return new NextCommandReply(FtpCommandCode.ACCT,
120                     ReplyCode.REPLY_332_NEED_ACCOUNT_FOR_LOGIN, null);
121         }
122         throw new Reply530Exception("Password is not valid");
123     }
124 
125     /**
126      * Set the account according to any implementation and could set the rootFromAuth. If NOOP is
127      * returned, isIdentifed must be TRUE.
128      * 
129      * @param account
130      * @return (NOOP,230) if the Account is OK, else return the following command that must follow
131      *         and the associated reply
132      * @throws Reply421Exception
133      *             if there is a problem during the authentication
134      * @throws Reply530Exception
135      *             if there is a problem during the authentication
136      */
137     @Override
138     protected NextCommandReply setBusinessAccount(String account)
139             throws Reply421Exception, Reply530Exception {
140         if (currentAuth == null) {
141             throw new Reply530Exception("ACCT needs a USER first");
142         }
143         if (currentAuth.isAccountValid(account)) {
144             // logger.debug("Account: {}", account);
145             setIsIdentified(true);
146             logger.info("User {} is authentified with account {}", user,
147                     account);
148             return new NextCommandReply(FtpCommandCode.NOOP,
149                     ReplyCode.REPLY_230_USER_LOGGED_IN, null);
150         }
151         throw new Reply530Exception("Account is not valid");
152     }
153 
154     public boolean isBusinessPathValid(String newPath) {
155         if (newPath == null) {
156             return false;
157         }
158         return newPath.startsWith(getBusinessPath());
159     }
160 
161     @Override
162     protected String setBusinessRootFromAuth() throws Reply421Exception {
163         String path = null;
164         if (account == null) {
165             path = FtpDir.SEPARATOR + user;
166         } else {
167             path = FtpDir.SEPARATOR + user + FtpDir.SEPARATOR +
168                     account;
169         }
170         String fullpath = getAbsolutePath(path);
171         File file = new File(fullpath);
172         if (!file.isDirectory()) {
173             throw new Reply421Exception("Filesystem not ready");
174         }
175         return path;
176     }
177 
178     public boolean isAdmin() {
179         if (currentAuth == null)
180             return false;
181         return currentAuth.isAdmin();
182     }
183 
184     /**
185      * Special Authentication for local execution
186      * 
187      * @param hostid
188      */
189     public void specialNoSessionAuth(String hostid) {
190         this.isIdentified = true;
191         SimpleAuth auth = new SimpleAuth(hostid, hostid, null, null, 0, null, 0);
192         currentAuth = auth;
193         setIsIdentified(true);
194         user = auth.getUser();
195         account = auth.getUser();
196         ((FtpSession) getSession()).setSpecialInit(this,
197                 new FileBasedDir(((FtpSession) getSession())),
198                 new FilesystemBasedFtpRestart(((FtpSession) getSession())));
199         try {
200             setBusinessRootFromAuth();
201         } catch (Reply421Exception e) {
202         }
203         getSession().getDir().initAfterIdentification();
204         currentAuth.setAdmin(true);
205     }
206 
207     /**
208      * @return the specialId
209      */
210     public long getSpecialId() {
211         return specialId;
212     }
213 
214     /**
215      * @param specialId
216      *            the specialId to set
217      */
218     public void setSpecialId(long specialId) {
219         this.specialId = specialId;
220     }
221 
222     /**
223      * 
224      * @return the associated Command Executor
225      */
226     public CommandExecutor getCommandExecutor() {
227         return this.currentAuth.getCommandExecutor();
228     }
229 }