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 }