1 /*
2 * This file is part of Waarp Project (named also Waarp or GG).
3 *
4 * Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5 * tags. See the COPYRIGHT.txt in the distribution for a full listing of
6 * individual contributors.
7 *
8 * All Waarp Project is free software: you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * Waarp . If not, see <http://www.gnu.org/licenses/>.
19 */
20 package org.waarp.common.file.filesystembased;
21
22 import org.waarp.common.command.NextCommandReply;
23 import org.waarp.common.command.ReplyCode;
24 import org.waarp.common.command.exception.Reply421Exception;
25 import org.waarp.common.command.exception.Reply530Exception;
26 import org.waarp.common.file.AbstractDir;
27 import org.waarp.common.file.AuthInterface;
28 import org.waarp.common.file.DirInterface;
29 import org.waarp.common.file.SessionInterface;
30 import org.waarp.common.utility.ParametersChecker;
31
32 import java.util.regex.Pattern;
33
34 /**
35 * Authentication implementation for Filesystem Based
36 */
37 public abstract class FilesystemBasedAuthImpl implements AuthInterface {
38 /**
39 * DOUBLE SLASH pattern
40 */
41 private static final Pattern DOUBLE_SLASH = Pattern.compile("//");
42 /**
43 * User name
44 */
45 protected String user;
46
47 /**
48 * Password
49 */
50 protected String password;
51
52 /**
53 * Is Identified
54 */
55 protected boolean isIdentified;
56
57 /**
58 * SessionInterface
59 */
60 protected final SessionInterface session;
61
62 /**
63 * Relative Path after Authentication
64 */
65 protected String rootFromAuth;
66
67 /**
68 * @param session
69 */
70 protected FilesystemBasedAuthImpl(final SessionInterface session) {
71 this.session = session;
72 isIdentified = false;
73 }
74
75 /**
76 * @return the session
77 */
78 @Override
79 public final SessionInterface getSession() {
80 return session;
81 }
82
83 /**
84 * Set the user according to any implementation and could set the
85 * rootFromAuth. If NOOP is returned,
86 * isIdentifed must be TRUE.
87 *
88 * @param user
89 *
90 * @return (NOOP, 230) if the user is OK, else return the following command
91 * that must follow (usually PASS) and
92 * the associated reply
93 *
94 * @throws Reply421Exception if there is a problem during the
95 * authentication
96 * @throws Reply530Exception if there is a problem during the
97 * authentication
98 */
99 protected abstract NextCommandReply setBusinessUser(String user)
100 throws Reply421Exception, Reply530Exception;
101
102 /**
103 * @param user the user to set
104 *
105 * @return (NOOP, 230) if the user is OK, else return the following command
106 * that must follow (usually PASS) and
107 * the associated reply
108 *
109 * @throws Reply421Exception if there is a problem during the
110 * authentication
111 * @throws Reply530Exception if there is a problem during the
112 * authentication
113 */
114 @Override
115 public final NextCommandReply setUser(final String user)
116 throws Reply421Exception, Reply530Exception {
117 final NextCommandReply next = setBusinessUser(user);
118 this.user = user;
119 if (next.reply == ReplyCode.REPLY_230_USER_LOGGED_IN) {
120 setRootFromAuth();
121 session.getDir().initAfterIdentification();
122 }
123 return next;
124 }
125
126 /**
127 * @return the user
128 */
129 @Override
130 public final String getUser() {
131 return user;
132 }
133
134 /**
135 * Set the password according to any implementation and could set the
136 * rootFromAuth. If NOOP is returned,
137 * isIdentifed must be TRUE.
138 *
139 * @param password
140 *
141 * @return (NOOP, 230) if the Password is OK, else return the following
142 * command that must follow (usually ACCT)
143 * and the associated reply
144 *
145 * @throws Reply421Exception if there is a problem during the
146 * authentication
147 * @throws Reply530Exception if there is a problem during the
148 * authentication
149 */
150 protected abstract NextCommandReply setBusinessPassword(String password)
151 throws Reply421Exception, Reply530Exception;
152
153 /**
154 * @param password the password to set
155 *
156 * @return (NOOP, 230) if the Password is OK, else return the following
157 * command that must follow (usually ACCT)
158 * and the associated reply
159 *
160 * @throws Reply421Exception if there is a problem during the
161 * authentication
162 * @throws Reply530Exception if there is a problem during the
163 * authentication
164 */
165 @Override
166 public final NextCommandReply setPassword(final String password)
167 throws Reply421Exception, Reply530Exception {
168 final NextCommandReply next = setBusinessPassword(password);
169 this.password = password;
170 if (next.reply == ReplyCode.REPLY_230_USER_LOGGED_IN) {
171 setRootFromAuth();
172 session.getDir().initAfterIdentification();
173 }
174 return next;
175 }
176
177 /**
178 * Set the Authentication to Identified or Not
179 *
180 * @param isIdentified
181 */
182 protected final void setIsIdentified(final boolean isIdentified) {
183 this.isIdentified = isIdentified;
184 }
185
186 /**
187 * Is the current Authentication OK for full identification. It must be true
188 * after a correct sequence of
189 * identification: At most, it is true when setAccount is OK. It could be
190 * positive before (user name only,
191 * user+password only).<br>
192 * In the current implementation, as USER+PASS+ACCT are needed, it will be
193 * true only after a correct ACCT.
194 *
195 * @return True if the user has a positive login, else False
196 */
197 @Override
198 public final boolean isIdentified() {
199 return isIdentified;
200 }
201
202 /**
203 * @return the root relative path from authentication if any or null if the
204 * default is used (default is /user
205 * or /user/account)
206 *
207 * @throws Reply421Exception if the business root is not available
208 */
209 protected abstract String setBusinessRootFromAuth() throws Reply421Exception;
210
211 /**
212 * Set the root relative Path from current status of Authentication (should
213 * be
214 * the highest level for the
215 * current authentication). If setBusinessRootFromAuth returns null, by
216 * default set /user or /user/account.
217 *
218 * @throws Reply421Exception if the business root is not available
219 */
220 protected void setRootFromAuth() throws Reply421Exception {
221 rootFromAuth = setBusinessRootFromAuth();
222 if (rootFromAuth == null) {
223 rootFromAuth = DirInterface.SEPARATOR + user;
224 }
225 }
226
227 @Override
228 public final String getBusinessPath() {
229 return rootFromAuth;
230 }
231
232 /**
233 * Business implementation of clean
234 */
235 protected abstract void businessClean();
236
237 /**
238 * Clean object
239 */
240 @Override
241 public void clear() {
242 businessClean();
243 user = null;
244 password = null;
245 rootFromAuth = null;
246 isIdentified = false;
247 }
248
249 /**
250 * Return the full path as a String (with mount point).
251 *
252 * @param path relative path including business one (may be null or
253 * empty)
254 *
255 * @return the full path as a String
256 */
257 public final String getAbsolutePath(final String path) {
258 if (ParametersChecker.isEmpty(path)) {
259 return getBaseDirectory();
260 }
261 return AbstractDir.normalizePath(
262 getBaseDirectory() + DirInterface.SEPARATOR + path);
263 }
264
265 /**
266 * Return the relative path from a file (without mount point)
267 *
268 * @param file (full path with mount point)
269 *
270 * @return the relative path from a file
271 */
272 @Override
273 public final String getRelativePath(final String file) {
274 // Work around Windows path '\'
275 return DOUBLE_SLASH.matcher(
276 file.replaceFirst(AbstractDir.normalizePath(getBaseDirectory()), ""))
277 .replaceAll("/");
278 }
279 }