This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View File

@@ -0,0 +1,170 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.users;
import java.util.Iterator;
import org.apache.catalina.Group;
import org.apache.catalina.Role;
import org.apache.catalina.User;
import org.apache.catalina.UserDatabase;
/**
* <p>Convenience base class for {@link Group} implementations.</p>
*
* @author Craig R. McClanahan
* @since 4.1
*/
public abstract class AbstractGroup implements Group {
// ----------------------------------------------------- Instance Variables
/**
* The description of this group.
*/
protected String description = null;
/**
* The group name of this group.
*/
protected String groupname = null;
// ------------------------------------------------------------- Properties
/**
* Return the description of this group.
*/
@Override
public String getDescription() {
return this.description;
}
/**
* Set the description of this group.
*
* @param description The new description
*/
@Override
public void setDescription(String description) {
this.description = description;
}
/**
* Return the group name of this group, which must be unique
* within the scope of a {@link UserDatabase}.
*/
@Override
public String getGroupname() {
return this.groupname;
}
/**
* Set the group name of this group, which must be unique
* within the scope of a {@link UserDatabase}.
*
* @param groupname The new group name
*/
@Override
public void setGroupname(String groupname) {
this.groupname = groupname;
}
/**
* Return the set of {@link Role}s assigned specifically to this group.
*/
@Override
public abstract Iterator<Role> getRoles();
/**
* Return the {@link UserDatabase} within which this Group is defined.
*/
@Override
public abstract UserDatabase getUserDatabase();
/**
* Return an Iterator over the set of {@link org.apache.catalina.User}s that
* are members of this group.
*/
@Override
public abstract Iterator<User> getUsers();
// --------------------------------------------------------- Public Methods
/**
* Add a new {@link Role} to those assigned specifically to this group.
*
* @param role The new role
*/
@Override
public abstract void addRole(Role role);
/**
* Is this group specifically assigned the specified {@link Role}?
*
* @param role The role to check
*/
@Override
public abstract boolean isInRole(Role role);
/**
* Remove a {@link Role} from those assigned to this group.
*
* @param role The old role
*/
@Override
public abstract void removeRole(Role role);
/**
* Remove all {@link Role}s from those assigned to this group.
*/
@Override
public abstract void removeRoles();
// ------------------------------------------------------ Principal Methods
/**
* Make the principal name the same as the group name.
*/
@Override
public String getName() {
return getGroupname();
}
}

View File

@@ -0,0 +1,117 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.users;
import org.apache.catalina.Role;
import org.apache.catalina.UserDatabase;
/**
* <p>Convenience base class for {@link Role} implementations.</p>
*
* @author Craig R. McClanahan
* @since 4.1
*/
public abstract class AbstractRole implements Role {
// ----------------------------------------------------- Instance Variables
/**
* The description of this Role.
*/
protected String description = null;
/**
* The role name of this Role.
*/
protected String rolename = null;
// ------------------------------------------------------------- Properties
/**
* Return the description of this role.
*/
@Override
public String getDescription() {
return this.description;
}
/**
* Set the description of this role.
*
* @param description The new description
*/
@Override
public void setDescription(String description) {
this.description = description;
}
/**
* Return the role name of this role, which must be unique
* within the scope of a {@link UserDatabase}.
*/
@Override
public String getRolename() {
return this.rolename;
}
/**
* Set the role name of this role, which must be unique
* within the scope of a {@link UserDatabase}.
*
* @param rolename The new role name
*/
@Override
public void setRolename(String rolename) {
this.rolename = rolename;
}
/**
* Return the {@link UserDatabase} within which this Role is defined.
*/
@Override
public abstract UserDatabase getUserDatabase();
// --------------------------------------------------------- Public Methods
// ------------------------------------------------------ Principal Methods
/**
* Make the principal name the same as the role name.
*/
@Override
public String getName() {
return getRolename();
}
}

View File

@@ -0,0 +1,227 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.users;
import java.util.Iterator;
import org.apache.catalina.Group;
import org.apache.catalina.Role;
import org.apache.catalina.User;
/**
* <p>Convenience base class for {@link User} implementations.</p>
*
* @author Craig R. McClanahan
* @since 4.1
*/
public abstract class AbstractUser implements User {
// ----------------------------------------------------- Instance Variables
/**
* The full name of this user.
*/
protected String fullName = null;
/**
* The logon password of this user.
*/
protected String password = null;
/**
* The logon username of this user.
*/
protected String username = null;
// ------------------------------------------------------------- Properties
/**
* Return the full name of this user.
*/
@Override
public String getFullName() {
return this.fullName;
}
/**
* Set the full name of this user.
*
* @param fullName The new full name
*/
@Override
public void setFullName(String fullName) {
this.fullName = fullName;
}
/**
* Return the set of {@link Group}s to which this user belongs.
*/
@Override
public abstract Iterator<Group> getGroups();
/**
* Return the logon password of this user, optionally prefixed with the
* identifier of an encoding scheme surrounded by curly braces, such as
* <code>{md5}xxxxx</code>.
*/
@Override
public String getPassword() {
return this.password;
}
/**
* Set the logon password of this user, optionally prefixed with the
* identifier of an encoding scheme surrounded by curly braces, such as
* <code>{md5}xxxxx</code>.
*
* @param password The new logon password
*/
@Override
public void setPassword(String password) {
this.password = password;
}
/**
* Return the set of {@link Role}s assigned specifically to this user.
*/
@Override
public abstract Iterator<Role> getRoles();
/**
* Return the logon username of this user, which must be unique
* within the scope of a {@link org.apache.catalina.UserDatabase}.
*/
@Override
public String getUsername() {
return this.username;
}
/**
* Set the logon username of this user, which must be unique within
* the scope of a {@link org.apache.catalina.UserDatabase}.
*
* @param username The new logon username
*/
@Override
public void setUsername(String username) {
this.username = username;
}
// --------------------------------------------------------- Public Methods
/**
* Add a new {@link Group} to those this user belongs to.
*
* @param group The new group
*/
@Override
public abstract void addGroup(Group group);
/**
* Add a new {@link Role} to those assigned specifically to this user.
*
* @param role The new role
*/
@Override
public abstract void addRole(Role role);
/**
* Is this user in the specified {@link Group}?
*
* @param group The group to check
*/
@Override
public abstract boolean isInGroup(Group group);
/**
* Is this user specifically assigned the specified {@link Role}? This
* method does <strong>NOT</strong> check for roles inherited based on
* {@link Group} membership.
*
* @param role The role to check
*/
@Override
public abstract boolean isInRole(Role role);
/**
* Remove a {@link Group} from those this user belongs to.
*
* @param group The old group
*/
@Override
public abstract void removeGroup(Group group);
/**
* Remove all {@link Group}s from those this user belongs to.
*/
@Override
public abstract void removeGroups();
/**
* Remove a {@link Role} from those assigned to this user.
*
* @param role The old role
*/
@Override
public abstract void removeRole(Role role);
/**
* Remove all {@link Role}s from those assigned to this user.
*/
@Override
public abstract void removeRoles();
// ------------------------------------------------------ Principal Methods
/**
* Make the principal name the same as the group name.
*/
@Override
public String getName() {
return getUsername();
}
}

View File

@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.users;
/**
* Manifest constants for this Java package.
*
*
* @author Craig R. McClanahan
* @since 4.1
*/
public final class Constants {
public static final String Package = "org.apache.catalina.users";
}

View File

@@ -0,0 +1,30 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
memoryUserDatabase.fileClose=Failed to close [{0}]
memoryUserDatabase.fileDelete=Failed to delete [{0}]
memoryUserDatabase.fileNotFound=The specified user database [{0}] could not be found
memoryUserDatabase.notPersistable=User database is not persistable - no write permissions on directory
memoryUserDatabase.nullGroup=Null or zero length group name specified. The group will be ignored.
memoryUserDatabase.nullRole=Null or zero length role name specified. The role will be ignored.
memoryUserDatabase.nullUser=Null or zero length user name specified. The user will be ignored.
memoryUserDatabase.readOnly=User database has been configured to be read only. Changes cannot be saved
memoryUserDatabase.reload=Reloading memory user database [{0}] from updated source [{1}]
memoryUserDatabase.reloadError=Error reloading memory user database [{0}] from updated source [{1}]
memoryUserDatabase.renameNew=Cannot rename new file to [{0}]
memoryUserDatabase.renameOld=Cannot rename original file to [{0}]
memoryUserDatabase.restoreOrig=Cannot restore [{0}] to original file
memoryUserDatabase.writeException=IOException writing to [{0}]
memoryUserDatabase.xmlFeatureEncoding=Exception configuring digester to permit java encoding names in XML files. Only IANA encoding names will be supported.

View File

@@ -0,0 +1,16 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
memoryUserDatabase.nullRole=Spezifizierter Rollenname ist null oder ist null Zeichen lang und wird daher ignoriert

View File

@@ -0,0 +1,26 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
memoryUserDatabase.fileNotFound=El usuario de base de datos especificado [{0}] no pudo ser encontrado
memoryUserDatabase.notPersistable=La base de datos de usuario no es persistible - no hay permisos de grabación sobre el directorio
memoryUserDatabase.nullGroup=Se ha especificado un nombre de grupo nulo o de tamaño cero. Se ignora el grupo.
memoryUserDatabase.nullRole=Se ha especificado un nombre rol nulo o de tamaño cero. Se ignora el rol.
memoryUserDatabase.nullUser=Se ha especificado un nombre de usuario nulo o de tamaño cero. Se ignora el usuario.
memoryUserDatabase.readOnly=User database has been configured to be read only. Changes cannot be saved
memoryUserDatabase.renameNew=Imposible de renombrar el archivo nuevo a [{0}]
memoryUserDatabase.renameOld=Imposible de renombrar el archivo original a [{0}]
memoryUserDatabase.restoreOrig=No se puede restablecer [{0}] al archivo original
memoryUserDatabase.writeException=IOException durante la escritura hacia [{0}]
memoryUserDatabase.xmlFeatureEncoding=Excepción al configurar el resumidor para permitir nombres codificados en java en los ficheros XML. Sólo se soportarán los nombres con codificación IANA.

View File

@@ -0,0 +1,30 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
memoryUserDatabase.fileClose=Echec de fermeture [{0}]
memoryUserDatabase.fileDelete=Impossible d''effacer [{0}]
memoryUserDatabase.fileNotFound=La base d''utilisateurs spécifiée [{0}] n''a pas été trouvée
memoryUserDatabase.notPersistable=La base de donnée des utilisateurs ne peut pas être persistée, il n'y a pas de permissions d'écriture sur le répertoire
memoryUserDatabase.nullGroup=Un nom de groupe nul ou vide a été spécifié, le groupe sera ignoré
memoryUserDatabase.nullRole=Le nom du rôle spécifié est nul ou a une taille de zéro. Le rôle sera ignoré.
memoryUserDatabase.nullUser=Le nom d'utilisateur est null ou a une longueur de zéro, il sera ignoré
memoryUserDatabase.readOnly=La base de donnée utilisateurs a été configurée en mode lecture seule, les modifications ne peuvent être sauvegardées
memoryUserDatabase.reload=Rechargement de la base de données des utilisateurs [{0}] à partir de la source mise à jour [{1}]
memoryUserDatabase.reloadError=Erreur de rechargement de la base de donnée utilisateurs [{0}] à partir de la source mise à jour [{1}]
memoryUserDatabase.renameNew=Impossible de renommer le nouveau fichier en [{0}]
memoryUserDatabase.renameOld=Impossible de renommer le fichier d''origine en [{0}]
memoryUserDatabase.restoreOrig=Impossible de restaurer [{0}] vers le fichier d''origine
memoryUserDatabase.writeException=IOException lors de l''écriture vers [{0}]
memoryUserDatabase.xmlFeatureEncoding=Exception lors de la configuration du Digester pour permettre des noms d'encodage Java dans les fichiers XML, seuls le noms IANA seront supportés

View File

@@ -0,0 +1,30 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
memoryUserDatabase.fileClose=[{0}]のクローズに失敗しました
memoryUserDatabase.fileDelete=[{0}]を削除できませんでした
memoryUserDatabase.fileNotFound=ユーザー情報データベースとして指定された [{0}] は存在しません。
memoryUserDatabase.notPersistable=ユーザーデータベースは永続的ではありません - ディレクトリに対する書き込み権限がありません。
memoryUserDatabase.nullGroup=Nullまたは長さゼロのグループ名が指定されています。 グループは無視されます。
memoryUserDatabase.nullRole=NULLまたは長さゼロのロール名が指定されています。 ロールは無視されます。
memoryUserDatabase.nullUser=Nullまたは長さゼロのユーザー名が指定されています。 ユーザーは無視されます。
memoryUserDatabase.readOnly=ユーザー情報データベースは読み取り専用になっています。変更を保存できません。
memoryUserDatabase.reload=更新されたソース[{1}]からメモリユーザーデータベース[{0}]を再ロードしています
memoryUserDatabase.reloadError=更新されたソース[{1}]からメモリユーザーデータベース[{0}]を再ロード中にエラーが発生しました。
memoryUserDatabase.renameNew=新しいファイル名を [{0}] に変更できません
memoryUserDatabase.renameOld=元のファイル名を [{0}] に変更できません
memoryUserDatabase.restoreOrig=[{0}]を元のファイルに復元できません
memoryUserDatabase.writeException=[{0}] に書き込み中のIOExceptionです
memoryUserDatabase.xmlFeatureEncoding=XMLファイルのJavaエンコーディング名を許可するためにdigesterを設定する際の例外。 IANAのエンコーディング名のみがサポートされます。

View File

@@ -0,0 +1,30 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
memoryUserDatabase.fileClose=[{0}]을(를) 닫지 못했습니다.
memoryUserDatabase.fileDelete=[{0}]을(를) 삭제하지 못했습니다.
memoryUserDatabase.fileNotFound=지정된 사용자 데이터베이스 [{0}]을(를) 찾을 수 없었습니다.
memoryUserDatabase.notPersistable=사용자 데이터베이스에 저장할 수 없습니다 - 디렉토리에 쓰기 권한이 없음.
memoryUserDatabase.nullGroup=널 또는 길이가 0인 그룹 이름이 지정되었습니다. 해당 그룹은 무시될 것입니다.
memoryUserDatabase.nullRole=널이거나 길이가 0인 문자열로, 역할 이름이 지정되었습니다. 해당 역할은 무시됩니다.
memoryUserDatabase.nullUser=사용자 이름에 널이거나 길이가 0인 문자열이 지정되었습니다. 이 사용자는 무시될 것입니다.
memoryUserDatabase.readOnly=사용자 데이터베이스는 읽기 전용으로 설정되어 있습니다. 변경 사항들이 저장될 수 없습니다.
memoryUserDatabase.reload=변경된 소스 [{1}](으)로부터 메모리 사용자 데이터베이스 [{0}]을(를) 다시 로드합니다.
memoryUserDatabase.reloadError=메모리 사용자 데이터베이스 [{0}]을(를), 변경된 원본 [{1}](으)로부터 다시 로드하는 중 오류 발생
memoryUserDatabase.renameNew=새 파일을 [{0}](으)로 이름을 변경할 수 없습니다.
memoryUserDatabase.renameOld=원본 파일을 [{0}](으)로 이름을 변경할 수 없습니다.
memoryUserDatabase.restoreOrig=[{0}] 파일을 원본 파일로 복구할 수 없습니다.
memoryUserDatabase.writeException=[{0}]에 데이터를 쓰는 중 IOException 발생
memoryUserDatabase.xmlFeatureEncoding=XML 파일들 내에서 자바 인코딩 이름들을 허용하기 위하여, Digester를 설정하던 중 예외 발생. 오직 IANA 인코딩 이름들만 지원될 것입니다.

View File

@@ -0,0 +1,25 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
memoryUserDatabase.fileClose=关闭 [{0}] 失败
memoryUserDatabase.fileDelete=无法删除 [{0}]
memoryUserDatabase.fileNotFound=指定用户数据库[{0}]未找到
memoryUserDatabase.notPersistable=用户数据库不可持久化 - 对目录没有写入权限
memoryUserDatabase.nullRole=指定的角色名为Null或着长度为0。角色将被忽略
memoryUserDatabase.readOnly=用户数据库已被设为只读。修改无法保存
memoryUserDatabase.reloadError=从更新后的源 [{1}] 重新加载内存用户数据库 [{0}] 时出错
memoryUserDatabase.renameNew=无法将新文件重命名为 [{0}]
memoryUserDatabase.renameOld=原文件无法改名为[{0}]
memoryUserDatabase.restoreOrig=无法往原始文件中保存[{0}]

View File

@@ -0,0 +1,199 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.users;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.catalina.Role;
import org.apache.catalina.User;
import org.apache.catalina.UserDatabase;
import org.apache.tomcat.util.buf.StringUtils;
import org.apache.tomcat.util.buf.StringUtils.Function;
/**
* <p>Concrete implementation of {@link org.apache.catalina.Group} for the
* {@link MemoryUserDatabase} implementation of {@link UserDatabase}.</p>
*
* @author Craig R. McClanahan
* @since 4.1
*/
public class MemoryGroup extends AbstractGroup {
// ----------------------------------------------------------- Constructors
/**
* Package-private constructor used by the factory method in
* {@link MemoryUserDatabase}.
*
* @param database The {@link MemoryUserDatabase} that owns this group
* @param groupname Group name of this group
* @param description Description of this group
*/
MemoryGroup(MemoryUserDatabase database,
String groupname, String description) {
super();
this.database = database;
setGroupname(groupname);
setDescription(description);
}
// ----------------------------------------------------- Instance Variables
/**
* The {@link MemoryUserDatabase} that owns this group.
*/
protected final MemoryUserDatabase database;
/**
* The set of {@link Role}s associated with this group.
*/
protected final ArrayList<Role> roles = new ArrayList<>();
// ------------------------------------------------------------- Properties
/**
* Return the set of {@link Role}s assigned specifically to this group.
*/
@Override
public Iterator<Role> getRoles() {
synchronized (roles) {
return roles.iterator();
}
}
/**
* Return the {@link UserDatabase} within which this Group is defined.
*/
@Override
public UserDatabase getUserDatabase() {
return this.database;
}
/**
* Return the set of {@link org.apache.catalina.User}s that are members of this group.
*/
@Override
public Iterator<User> getUsers() {
List<User> results = new ArrayList<>();
Iterator<User> users = database.getUsers();
while (users.hasNext()) {
User user = users.next();
if (user.isInGroup(this)) {
results.add(user);
}
}
return results.iterator();
}
// --------------------------------------------------------- Public Methods
/**
* Add a new {@link Role} to those assigned specifically to this group.
*
* @param role The new role
*/
@Override
public void addRole(Role role) {
synchronized (roles) {
if (!roles.contains(role)) {
roles.add(role);
}
}
}
/**
* Is this group specifically assigned the specified {@link Role}?
*
* @param role The role to check
*/
@Override
public boolean isInRole(Role role) {
synchronized (roles) {
return roles.contains(role);
}
}
/**
* Remove a {@link Role} from those assigned to this group.
*
* @param role The old role
*/
@Override
public void removeRole(Role role) {
synchronized (roles) {
roles.remove(role);
}
}
/**
* Remove all {@link Role}s from those assigned to this group.
*/
@Override
public void removeRoles() {
synchronized (roles) {
roles.clear();
}
}
/**
* <p>Return a String representation of this group in XML format.</p>
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder("<group groupname=\"");
sb.append(groupname);
sb.append("\"");
if (description != null) {
sb.append(" description=\"");
sb.append(description);
sb.append("\"");
}
synchronized (roles) {
if (roles.size() > 0) {
sb.append(" roles=\"");
StringUtils.join(roles, ',', new Function<Role>(){
@Override public String apply(Role t) { return t.getRolename(); }}, sb);
sb.append("\"");
}
}
sb.append("/>");
return sb.toString();
}
}

View File

@@ -0,0 +1,99 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.users;
import org.apache.catalina.UserDatabase;
/**
* <p>Concrete implementation of {@link org.apache.catalina.Role} for the
* {@link MemoryUserDatabase} implementation of {@link UserDatabase}.</p>
*
* @author Craig R. McClanahan
* @since 4.1
*/
public class MemoryRole extends AbstractRole {
// ----------------------------------------------------------- Constructors
/**
* Package-private constructor used by the factory method in
* {@link MemoryUserDatabase}.
*
* @param database The {@link MemoryUserDatabase} that owns this role
* @param rolename Role name of this role
* @param description Description of this role
*/
MemoryRole(MemoryUserDatabase database,
String rolename, String description) {
super();
this.database = database;
setRolename(rolename);
setDescription(description);
}
// ----------------------------------------------------- Instance Variables
/**
* The {@link MemoryUserDatabase} that owns this role.
*/
protected final MemoryUserDatabase database;
// ------------------------------------------------------------- Properties
/**
* Return the {@link UserDatabase} within which this role is defined.
*/
@Override
public UserDatabase getUserDatabase() {
return this.database;
}
// --------------------------------------------------------- Public Methods
/**
* <p>Return a String representation of this role in XML format.</p>
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder("<role rolename=\"");
sb.append(rolename);
sb.append("\"");
if (description != null) {
sb.append(" description=\"");
sb.append(description);
sb.append("\"");
}
sb.append("/>");
return sb.toString();
}
}

View File

@@ -0,0 +1,328 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.users;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.catalina.Group;
import org.apache.catalina.Role;
import org.apache.catalina.UserDatabase;
import org.apache.tomcat.util.buf.StringUtils;
import org.apache.tomcat.util.buf.StringUtils.Function;
import org.apache.tomcat.util.security.Escape;
/**
* <p>Concrete implementation of {@link org.apache.catalina.User} for the
* {@link MemoryUserDatabase} implementation of {@link UserDatabase}.</p>
*
* @author Craig R. McClanahan
* @since 4.1
*/
public class MemoryUser extends AbstractUser {
// ----------------------------------------------------------- Constructors
/**
* Package-private constructor used by the factory method in
* {@link MemoryUserDatabase}.
*
* @param database The {@link MemoryUserDatabase} that owns this user
* @param username Logon username of the new user
* @param password Logon password of the new user
* @param fullName Full name of the new user
*/
MemoryUser(MemoryUserDatabase database, String username,
String password, String fullName) {
super();
this.database = database;
setUsername(username);
setPassword(password);
setFullName(fullName);
}
// ----------------------------------------------------- Instance Variables
/**
* The {@link MemoryUserDatabase} that owns this user.
*/
protected final MemoryUserDatabase database;
/**
* The set of {@link Group}s that this user is a member of.
*/
protected final ArrayList<Group> groups = new ArrayList<>();
/**
* The set of {@link Role}s associated with this user.
*/
protected final ArrayList<Role> roles = new ArrayList<>();
// ------------------------------------------------------------- Properties
/**
* Return the set of {@link Group}s to which this user belongs.
*/
@Override
public Iterator<Group> getGroups() {
synchronized (groups) {
return groups.iterator();
}
}
/**
* Return the set of {@link Role}s assigned specifically to this user.
*/
@Override
public Iterator<Role> getRoles() {
synchronized (roles) {
return roles.iterator();
}
}
/**
* Return the {@link UserDatabase} within which this User is defined.
*/
@Override
public UserDatabase getUserDatabase() {
return this.database;
}
// --------------------------------------------------------- Public Methods
/**
* Add a new {@link Group} to those this user belongs to.
*
* @param group The new group
*/
@Override
public void addGroup(Group group) {
synchronized (groups) {
if (!groups.contains(group)) {
groups.add(group);
}
}
}
/**
* Add a new {@link Role} to those assigned specifically to this user.
*
* @param role The new role
*/
@Override
public void addRole(Role role) {
synchronized (roles) {
if (!roles.contains(role)) {
roles.add(role);
}
}
}
/**
* Is this user in the specified group?
*
* @param group The group to check
*/
@Override
public boolean isInGroup(Group group) {
synchronized (groups) {
return groups.contains(group);
}
}
/**
* Is this user specifically assigned the specified {@link Role}? This
* method does <strong>NOT</strong> check for roles inherited based on
* {@link Group} membership.
*
* @param role The role to check
*/
@Override
public boolean isInRole(Role role) {
synchronized (roles) {
return roles.contains(role);
}
}
/**
* Remove a {@link Group} from those this user belongs to.
*
* @param group The old group
*/
@Override
public void removeGroup(Group group) {
synchronized (groups) {
groups.remove(group);
}
}
/**
* Remove all {@link Group}s from those this user belongs to.
*/
@Override
public void removeGroups() {
synchronized (groups) {
groups.clear();
}
}
/**
* Remove a {@link Role} from those assigned to this user.
*
* @param role The old role
*/
@Override
public void removeRole(Role role) {
synchronized (roles) {
roles.remove(role);
}
}
/**
* Remove all {@link Role}s from those assigned to this user.
*/
@Override
public void removeRoles() {
synchronized (roles) {
roles.clear();
}
}
/**
* <p>Return a String representation of this user in XML format.</p>
*
* <p><strong>IMPLEMENTATION NOTE</strong> - For backwards compatibility,
* the reader that processes this entry will accept either
* <code>username</code> or <code>name</code> for the username
* property.</p>
* @return the XML representation
*/
public String toXml() {
StringBuilder sb = new StringBuilder("<user username=\"");
sb.append(Escape.xml(username));
sb.append("\" password=\"");
sb.append(Escape.xml(password));
sb.append("\"");
if (fullName != null) {
sb.append(" fullName=\"");
sb.append(Escape.xml(fullName));
sb.append("\"");
}
synchronized (groups) {
if (groups.size() > 0) {
sb.append(" groups=\"");
StringUtils.join(groups, ',', new Function<Group>() {
@Override public String apply(Group t) {
return Escape.xml(t.getGroupname());
}
}, sb);
sb.append("\"");
}
}
synchronized (roles) {
if (roles.size() > 0) {
sb.append(" roles=\"");
StringUtils.join(roles, ',', new Function<Role>() {
@Override public String apply(Role t) {
return Escape.xml(t.getRolename());
}
}, sb);
sb.append("\"");
}
}
sb.append("/>");
return sb.toString();
}
/**
* <p>Return a String representation of this user.</p>
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder("User username=\"");
sb.append(Escape.xml(username));
sb.append("\"");
if (fullName != null) {
sb.append(", fullName=\"");
sb.append(Escape.xml(fullName));
sb.append("\"");
}
synchronized (groups) {
if (groups.size() > 0) {
sb.append(", groups=\"");
StringUtils.join(groups, ',', new Function<Group>() {
@Override public String apply(Group t) {
return Escape.xml(t.getGroupname());
}
}, sb);
sb.append("\"");
}
}
synchronized (roles) {
if (roles.size() > 0) {
sb.append(", roles=\"");
StringUtils.join(roles, ',', new Function<Role>() {
@Override public String apply(Role t) {
return Escape.xml(t.getRolename());
}
}, sb);
sb.append("\"");
}
}
return sb.toString();
}
}

View File

@@ -0,0 +1,869 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.users;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.catalina.Globals;
import org.apache.catalina.Group;
import org.apache.catalina.Role;
import org.apache.catalina.User;
import org.apache.catalina.UserDatabase;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.digester.AbstractObjectCreationFactory;
import org.apache.tomcat.util.digester.Digester;
import org.apache.tomcat.util.file.ConfigFileLoader;
import org.apache.tomcat.util.res.StringManager;
import org.xml.sax.Attributes;
/**
* Concrete implementation of {@link UserDatabase} that loads all defined users,
* groups, and roles into an in-memory data structure, and uses a specified XML
* file for its persistent storage.
* <p>
* This class is thread-safe.
* <p>
* This class does not enforce what, in an RDBMS, would be called referential
* integrity. Concurrent modifications may result in inconsistent data such as
* a User retaining a reference to a Role that has been removed from the
* database.
*
* @author Craig R. McClanahan
* @since 4.1
*/
/*
* Implementation notes:
*
* Any operation that acts on a single element of the database (e.g. operations
* that create, read, update or delete a user, role or group) must first obtain
* the read lock. Operations that return iterators for users, roles or groups
* also fall into this category.
*
* Iterators must always be created from copies of the data to prevent possible
* corruption of the iterator due to the remove of all elements from the
* underlying Map that would occur during a subsequent re-loading of the
* database.
*
* Any operation that acts on multiple elements and expects the database to
* remain consistent during the operation (e.g. saving or loading the database)
* must first obtain the write lock.
*/
public class MemoryUserDatabase implements UserDatabase {
private static final Log log = LogFactory.getLog(MemoryUserDatabase.class);
private static final StringManager sm = StringManager.getManager(MemoryUserDatabase.class);
// ----------------------------------------------------------- Constructors
/**
* Create a new instance with default values.
*/
public MemoryUserDatabase() {
this(null);
}
/**
* Create a new instance with the specified values.
*
* @param id Unique global identifier of this user database
*/
public MemoryUserDatabase(String id) {
this.id = id;
}
// ----------------------------------------------------- Instance Variables
/**
* The set of {@link Group}s defined in this database, keyed by group name.
*/
protected final Map<String, Group> groups = new ConcurrentHashMap<>();
/**
* The unique global identifier of this user database.
*/
protected final String id;
/**
* The relative (to <code>catalina.base</code>) or absolute pathname to the
* XML file in which we will save our persistent information.
*/
protected String pathname = "conf/tomcat-users.xml";
/**
* The relative or absolute pathname to the file in which our old
* information is stored while renaming is in progress.
*/
protected String pathnameOld = pathname + ".old";
/**
* The relative or absolute pathname of the file in which we write our new
* information prior to renaming.
*/
protected String pathnameNew = pathname + ".new";
/**
* A flag, indicating if the user database is read only.
*/
protected boolean readonly = true;
/**
* The set of {@link Role}s defined in this database, keyed by role name.
*/
protected final Map<String, Role> roles = new ConcurrentHashMap<>();
/**
* The set of {@link User}s defined in this database, keyed by user name.
*/
protected final Map<String, User> users = new ConcurrentHashMap<>();
private final ReentrantReadWriteLock dbLock = new ReentrantReadWriteLock();
private final Lock readLock = dbLock.readLock();
private final Lock writeLock = dbLock.writeLock();
private volatile long lastModified = 0;
private boolean watchSource = true;
// ------------------------------------------------------------- Properties
/**
* @return the set of {@link Group}s defined in this user database.
*/
@Override
public Iterator<Group> getGroups() {
readLock.lock();
try {
return new ArrayList<>(groups.values()).iterator();
} finally {
readLock.unlock();
}
}
/**
* @return the unique global identifier of this user database.
*/
@Override
public String getId() {
return this.id;
}
/**
* @return the relative or absolute pathname to the persistent storage file.
*/
public String getPathname() {
return this.pathname;
}
/**
* Set the relative or absolute pathname to the persistent storage file.
*
* @param pathname The new pathname
*/
public void setPathname(String pathname) {
this.pathname = pathname;
this.pathnameOld = pathname + ".old";
this.pathnameNew = pathname + ".new";
}
/**
* @return the readonly status of the user database
*/
public boolean getReadonly() {
return this.readonly;
}
/**
* Setting the readonly status of the user database
*
* @param readonly the new status
*/
public void setReadonly(boolean readonly) {
this.readonly = readonly;
}
public boolean getWatchSource() {
return watchSource;
}
public void setWatchSource(boolean watchSource) {
this.watchSource = watchSource;
}
/**
* @return the set of {@link Role}s defined in this user database.
*/
@Override
public Iterator<Role> getRoles() {
readLock.lock();
try {
return new ArrayList<>(roles.values()).iterator();
} finally {
readLock.unlock();
}
}
/**
* @return the set of {@link User}s defined in this user database.
*/
@Override
public Iterator<User> getUsers() {
readLock.lock();
try {
return new ArrayList<>(users.values()).iterator();
} finally {
readLock.unlock();
}
}
// --------------------------------------------------------- Public Methods
/**
* Finalize access to this user database.
*
* @exception Exception if any exception is thrown during closing
*/
@Override
public void close() throws Exception {
writeLock.lock();
try {
save();
users.clear();
groups.clear();
roles.clear();
} finally {
writeLock.unlock();
}
}
/**
* Create and return a new {@link Group} defined in this user database.
*
* @param groupname The group name of the new group (must be unique)
* @param description The description of this group
*/
@Override
public Group createGroup(String groupname, String description) {
if (groupname == null || groupname.length() == 0) {
String msg = sm.getString("memoryUserDatabase.nullGroup");
log.warn(msg);
throw new IllegalArgumentException(msg);
}
MemoryGroup group = new MemoryGroup(this, groupname, description);
readLock.lock();
try {
groups.put(group.getGroupname(), group);
} finally {
readLock.unlock();
}
return group;
}
/**
* Create and return a new {@link Role} defined in this user database.
*
* @param rolename The role name of the new group (must be unique)
* @param description The description of this group
*/
@Override
public Role createRole(String rolename, String description) {
if (rolename == null || rolename.length() == 0) {
String msg = sm.getString("memoryUserDatabase.nullRole");
log.warn(msg);
throw new IllegalArgumentException(msg);
}
MemoryRole role = new MemoryRole(this, rolename, description);
readLock.lock();
try {
roles.put(role.getRolename(), role);
} finally {
readLock.unlock();
}
return role;
}
/**
* Create and return a new {@link User} defined in this user database.
*
* @param username The logon username of the new user (must be unique)
* @param password The logon password of the new user
* @param fullName The full name of the new user
*/
@Override
public User createUser(String username, String password, String fullName) {
if (username == null || username.length() == 0) {
String msg = sm.getString("memoryUserDatabase.nullUser");
log.warn(msg);
throw new IllegalArgumentException(msg);
}
MemoryUser user = new MemoryUser(this, username, password, fullName);
readLock.lock();
try {
users.put(user.getUsername(), user);
} finally {
readLock.unlock();
}
return user;
}
/**
* Return the {@link Group} with the specified group name, if any; otherwise
* return <code>null</code>.
*
* @param groupname Name of the group to return
*/
@Override
public Group findGroup(String groupname) {
readLock.lock();
try {
return groups.get(groupname);
} finally {
readLock.unlock();
}
}
/**
* Return the {@link Role} with the specified role name, if any; otherwise
* return <code>null</code>.
*
* @param rolename Name of the role to return
*/
@Override
public Role findRole(String rolename) {
readLock.lock();
try {
return roles.get(rolename);
} finally {
readLock.unlock();
}
}
/**
* Return the {@link User} with the specified user name, if any; otherwise
* return <code>null</code>.
*
* @param username Name of the user to return
*/
@Override
public User findUser(String username) {
readLock.lock();
try {
return users.get(username);
} finally {
readLock.unlock();
}
}
/**
* Initialize access to this user database.
*
* @exception Exception if any exception is thrown during opening
*/
@Override
public void open() throws Exception {
writeLock.lock();
try {
// Erase any previous groups and users
users.clear();
groups.clear();
roles.clear();
String pathName = getPathname();
URI uri = ConfigFileLoader.getURI(pathName);
URLConnection uConn = null;
try {
URL url = uri.toURL();
uConn = url.openConnection();
InputStream is = uConn.getInputStream();
this.lastModified = uConn.getLastModified();
// Construct a digester to read the XML input file
Digester digester = new Digester();
try {
digester.setFeature(
"http://apache.org/xml/features/allow-java-encodings", true);
} catch (Exception e) {
log.warn(sm.getString("memoryUserDatabase.xmlFeatureEncoding"), e);
}
digester.addFactoryCreate("tomcat-users/group",
new MemoryGroupCreationFactory(this), true);
digester.addFactoryCreate("tomcat-users/role",
new MemoryRoleCreationFactory(this), true);
digester.addFactoryCreate("tomcat-users/user",
new MemoryUserCreationFactory(this), true);
// Parse the XML input to load this database
digester.parse(is);
} catch (IOException ioe) {
log.error(sm.getString("memoryUserDatabase.fileNotFound", pathName));
} catch (Exception e) {
// Fail safe on error
users.clear();
groups.clear();
roles.clear();
throw e;
} finally {
if (uConn != null) {
try {
// Can't close a uConn directly. Have to do it like this.
uConn.getInputStream().close();
} catch (IOException ioe) {
log.warn(sm.getString("memoryUserDatabase.fileClose", pathname), ioe);
}
}
}
} finally {
writeLock.unlock();
}
}
/**
* Remove the specified {@link Group} from this user database.
*
* @param group The group to be removed
*/
@Override
public void removeGroup(Group group) {
readLock.lock();
try {
Iterator<User> users = getUsers();
while (users.hasNext()) {
User user = users.next();
user.removeGroup(group);
}
groups.remove(group.getGroupname());
} finally {
readLock.unlock();
}
}
/**
* Remove the specified {@link Role} from this user database.
*
* @param role The role to be removed
*/
@Override
public void removeRole(Role role) {
readLock.lock();
try {
Iterator<Group> groups = getGroups();
while (groups.hasNext()) {
Group group = groups.next();
group.removeRole(role);
}
Iterator<User> users = getUsers();
while (users.hasNext()) {
User user = users.next();
user.removeRole(role);
}
roles.remove(role.getRolename());
} finally {
readLock.unlock();
}
}
/**
* Remove the specified {@link User} from this user database.
*
* @param user The user to be removed
*/
@Override
public void removeUser(User user) {
readLock.lock();
try {
users.remove(user.getUsername());
} finally {
readLock.unlock();
}
}
/**
* Check for permissions to save this user database to persistent storage
* location.
*
* @return <code>true</code> if the database is writable
*/
public boolean isWriteable() {
File file = new File(pathname);
if (!file.isAbsolute()) {
file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathname);
}
File dir = file.getParentFile();
return dir.exists() && dir.isDirectory() && dir.canWrite();
}
/**
* Save any updated information to the persistent storage location for this
* user database.
*
* @exception Exception if any exception is thrown during saving
*/
@Override
public void save() throws Exception {
if (getReadonly()) {
log.error(sm.getString("memoryUserDatabase.readOnly"));
return;
}
if (!isWriteable()) {
log.warn(sm.getString("memoryUserDatabase.notPersistable"));
return;
}
// Write out contents to a temporary file
File fileNew = new File(pathnameNew);
if (!fileNew.isAbsolute()) {
fileNew = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathnameNew);
}
writeLock.lock();
try {
try (FileOutputStream fos = new FileOutputStream(fileNew);
OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
PrintWriter writer = new PrintWriter(osw)) {
// Print the file prolog
writer.println("<?xml version='1.0' encoding='utf-8'?>");
writer.println("<tomcat-users xmlns=\"http://tomcat.apache.org/xml\"");
writer.print(" ");
writer.println("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
writer.print(" ");
writer.println("xsi:schemaLocation=\"http://tomcat.apache.org/xml tomcat-users.xsd\"");
writer.println(" version=\"1.0\">");
// Print entries for each defined role, group, and user
Iterator<?> values = null;
values = getRoles();
while (values.hasNext()) {
writer.print(" ");
writer.println(values.next());
}
values = getGroups();
while (values.hasNext()) {
writer.print(" ");
writer.println(values.next());
}
values = getUsers();
while (values.hasNext()) {
writer.print(" ");
writer.println(((MemoryUser) values.next()).toXml());
}
// Print the file epilog
writer.println("</tomcat-users>");
// Check for errors that occurred while printing
if (writer.checkError()) {
throw new IOException(sm.getString("memoryUserDatabase.writeException",
fileNew.getAbsolutePath()));
}
} catch (IOException e) {
if (fileNew.exists() && !fileNew.delete()) {
log.warn(sm.getString("memoryUserDatabase.fileDelete", fileNew));
}
throw e;
}
this.lastModified = fileNew.lastModified();
} finally {
writeLock.unlock();
}
// Perform the required renames to permanently save this file
File fileOld = new File(pathnameOld);
if (!fileOld.isAbsolute()) {
fileOld = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathnameOld);
}
if (fileOld.exists() && !fileOld.delete()) {
throw new IOException(sm.getString("memoryUserDatabase.fileDelete", fileOld));
}
File fileOrig = new File(pathname);
if (!fileOrig.isAbsolute()) {
fileOrig = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathname);
}
if (fileOrig.exists()) {
if (!fileOrig.renameTo(fileOld)) {
throw new IOException(sm.getString("memoryUserDatabase.renameOld",
fileOld.getAbsolutePath()));
}
}
if (!fileNew.renameTo(fileOrig)) {
if (fileOld.exists()) {
if (!fileOld.renameTo(fileOrig)) {
log.warn(sm.getString("memoryUserDatabase.restoreOrig", fileOld));
}
}
throw new IOException(sm.getString("memoryUserDatabase.renameNew",
fileOrig.getAbsolutePath()));
}
if (fileOld.exists() && !fileOld.delete()) {
throw new IOException(sm.getString("memoryUserDatabase.fileDelete", fileOld));
}
}
public void backgroundProcess() {
if (!watchSource) {
return;
}
URI uri = ConfigFileLoader.getURI(getPathname());
URLConnection uConn = null;
try {
URL url = uri.toURL();
uConn = url.openConnection();
if (this.lastModified != uConn.getLastModified()) {
writeLock.lock();
try {
long detectedLastModified = uConn.getLastModified();
// Last modified as a resolution of 1s. Ensure that a write
// to the file is not in progress by ensuring that the last
// modified time is at least 2 seconds ago.
if (this.lastModified != detectedLastModified &&
detectedLastModified + 2000 < System.currentTimeMillis()) {
log.info(sm.getString("memoryUserDatabase.reload", id, uri));
open();
}
} finally {
writeLock.unlock();
}
}
} catch (Exception ioe) {
log.error(sm.getString("memoryUserDatabase.reloadError", id, uri), ioe);
} finally {
if (uConn != null) {
try {
// Can't close a uConn directly. Have to do it like this.
uConn.getInputStream().close();
} catch (IOException ioe) {
log.warn(sm.getString("memoryUserDatabase.fileClose", pathname), ioe);
}
}
}
}
/**
* Return a String representation of this UserDatabase.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder("MemoryUserDatabase[id=");
sb.append(this.id);
sb.append(",pathname=");
sb.append(pathname);
sb.append(",groupCount=");
sb.append(this.groups.size());
sb.append(",roleCount=");
sb.append(this.roles.size());
sb.append(",userCount=");
sb.append(this.users.size());
sb.append("]");
return sb.toString();
}
}
/**
* Digester object creation factory for group instances.
*/
class MemoryGroupCreationFactory extends AbstractObjectCreationFactory {
public MemoryGroupCreationFactory(MemoryUserDatabase database) {
this.database = database;
}
@Override
public Object createObject(Attributes attributes) {
String groupname = attributes.getValue("groupname");
if (groupname == null) {
groupname = attributes.getValue("name");
}
String description = attributes.getValue("description");
String roles = attributes.getValue("roles");
Group group = database.createGroup(groupname, description);
if (roles != null) {
while (roles.length() > 0) {
String rolename = null;
int comma = roles.indexOf(',');
if (comma >= 0) {
rolename = roles.substring(0, comma).trim();
roles = roles.substring(comma + 1);
} else {
rolename = roles.trim();
roles = "";
}
if (rolename.length() > 0) {
Role role = database.findRole(rolename);
if (role == null) {
role = database.createRole(rolename, null);
}
group.addRole(role);
}
}
}
return group;
}
private final MemoryUserDatabase database;
}
/**
* Digester object creation factory for role instances.
*/
class MemoryRoleCreationFactory extends AbstractObjectCreationFactory {
public MemoryRoleCreationFactory(MemoryUserDatabase database) {
this.database = database;
}
@Override
public Object createObject(Attributes attributes) {
String rolename = attributes.getValue("rolename");
if (rolename == null) {
rolename = attributes.getValue("name");
}
String description = attributes.getValue("description");
Role role = database.createRole(rolename, description);
return role;
}
private final MemoryUserDatabase database;
}
/**
* Digester object creation factory for user instances.
*/
class MemoryUserCreationFactory extends AbstractObjectCreationFactory {
public MemoryUserCreationFactory(MemoryUserDatabase database) {
this.database = database;
}
@Override
public Object createObject(Attributes attributes) {
String username = attributes.getValue("username");
if (username == null) {
username = attributes.getValue("name");
}
String password = attributes.getValue("password");
String fullName = attributes.getValue("fullName");
if (fullName == null) {
fullName = attributes.getValue("fullname");
}
String groups = attributes.getValue("groups");
String roles = attributes.getValue("roles");
User user = database.createUser(username, password, fullName);
if (groups != null) {
while (groups.length() > 0) {
String groupname = null;
int comma = groups.indexOf(',');
if (comma >= 0) {
groupname = groups.substring(0, comma).trim();
groups = groups.substring(comma + 1);
} else {
groupname = groups.trim();
groups = "";
}
if (groupname.length() > 0) {
Group group = database.findGroup(groupname);
if (group == null) {
group = database.createGroup(groupname, null);
}
user.addGroup(group);
}
}
}
if (roles != null) {
while (roles.length() > 0) {
String rolename = null;
int comma = roles.indexOf(',');
if (comma >= 0) {
rolename = roles.substring(0, comma).trim();
roles = roles.substring(comma + 1);
} else {
rolename = roles.trim();
roles = "";
}
if (rolename.length() > 0) {
Role role = database.findRole(rolename);
if (role == null) {
role = database.createRole(rolename, null);
}
user.addRole(role);
}
}
}
return user;
}
private final MemoryUserDatabase database;
}

View File

@@ -0,0 +1,116 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.users;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
/**
* <p>JNDI object creation factory for <code>MemoryUserDatabase</code>
* instances. This makes it convenient to configure a user database
* in the global JNDI resources associated with this Catalina instance,
* and then link to that resource for web applications that administer
* the contents of the user database.</p>
*
* <p>The <code>MemoryUserDatabase</code> instance is configured based
* on the following parameter values:</p>
* <ul>
* <li><strong>pathname</strong> - Absolute or relative (to the directory
* path specified by the <code>catalina.base</code> system property)
* pathname to the XML file from which our user information is loaded,
* and to which it is stored. [conf/tomcat-users.xml]</li>
* </ul>
*
* @author Craig R. McClanahan
* @since 4.1
*/
public class MemoryUserDatabaseFactory implements ObjectFactory {
// --------------------------------------------------------- Public Methods
/**
* <p>Create and return a new <code>MemoryUserDatabase</code> instance
* that has been configured according to the properties of the
* specified <code>Reference</code>. If you instance can be created,
* return <code>null</code> instead.</p>
*
* @param obj The possibly null object containing location or
* reference information that can be used in creating an object
* @param name The name of this object relative to <code>nameCtx</code>
* @param nameCtx The context relative to which the <code>name</code>
* parameter is specified, or <code>null</code> if <code>name</code>
* is relative to the default initial context
* @param environment The possibly null environment that is used in
* creating this object
*/
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable<?,?> environment)
throws Exception {
// We only know how to deal with <code>javax.naming.Reference</code>s
// that specify a class name of "org.apache.catalina.UserDatabase"
if ((obj == null) || !(obj instanceof Reference)) {
return null;
}
Reference ref = (Reference) obj;
if (!"org.apache.catalina.UserDatabase".equals(ref.getClassName())) {
return null;
}
// Create and configure a MemoryUserDatabase instance based on the
// RefAddr values associated with this Reference
MemoryUserDatabase database = new MemoryUserDatabase(name.toString());
RefAddr ra = null;
ra = ref.get("pathname");
if (ra != null) {
database.setPathname(ra.getContent().toString());
}
ra = ref.get("readonly");
if (ra != null) {
database.setReadonly(Boolean.parseBoolean(ra.getContent().toString()));
}
ra = ref.get("watchSource");
if (ra != null) {
database.setWatchSource(Boolean.parseBoolean(ra.getContent().toString()));
}
// Return the configured database instance
database.open();
// Don't try something we know won't work
if (!database.getReadonly())
database.save();
return database;
}
}

View File

@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<mbeans-descriptors>
<mbean name="MemoryUserDatabase"
className="org.apache.catalina.mbeans.MemoryUserDatabaseMBean"
description="In-memory user and group database"
domain="Users"
group="UserDatabase"
type="org.apache.catalina.users.MemoryUserDatabase">
<attribute name="groups"
description="MBean Names of all defined groups"
type="[Ljava.lang.String;"
writeable="false"/>
<attribute name="pathname"
description="Relative or absolute pathname to database file"
type="java.lang.String"/>
<attribute name="roles"
description="MBean Names of all defined roles"
type="[Ljava.lang.String;"
writeable="false"/>
<attribute name="users"
description="MBean Names of all defined users"
type="[Ljava.lang.String;"
writeable="false"/>
<attribute name="readonly"
description="No persistent save of the user database"
type="boolean"
writeable="false"/>
<attribute name="writeable"
description="Check if user database is writeable"
impact="INFO"
is="true"
writeable="false"/>
<operation name="createGroup"
description="Create new group and return MBean name"
impact="ACTION"
returnType="java.lang.String">
<parameter name="groupname"
description="Group name of the new group"
type="java.lang.String"/>
<parameter name="description"
description="Description of the new group"
type="java.lang.String"/>
</operation>
<operation name="createRole"
description="Create new role and return MBean name"
impact="ACTION"
returnType="java.lang.String">
<parameter name="rolename"
description="Role name of the new role"
type="java.lang.String"/>
<parameter name="description"
description="Description of the new role"
type="java.lang.String"/>
</operation>
<operation name="createUser"
description="Create new user and return MBean name"
impact="ACTION"
returnType="java.lang.String">
<parameter name="username"
description="User name of the new user"
type="java.lang.String"/>
<parameter name="password"
description="Password of the new user"
type="java.lang.String"/>
<parameter name="fullName"
description="Full name of the new user"
type="java.lang.String"/>
</operation>
<operation name="findGroup"
description="Return MBean Name of the specified group (if any)"
impact="INFO"
returnType="java.lang.String">
<parameter name="groupname"
description="Group name of the requested group"
type="java.lang.String"/>
</operation>
<operation name="findRole"
description="Return MBean Name of the specified role (if any)"
impact="INFO"
returnType="java.lang.String">
<parameter name="rolename"
description="Role name of the requested role"
type="java.lang.String"/>
</operation>
<operation name="findUser"
description="Return MBean Name of the specified user (if any)"
impact="INFO"
returnType="java.lang.String">
<parameter name="username"
description="User name of the requested user"
type="java.lang.String"/>
</operation>
<operation name="removeGroup"
description="Remove existing group (and all user memberships)"
impact="ACTION"
returnType="void">
<parameter name="groupname"
description="Group name of the group to remove"
type="java.lang.String"/>
</operation>
<operation name="removeRole"
description="Remove existing role"
impact="ACTION"
returnType="void">
<parameter name="rolename"
description="Role name of the role to remove"
type="java.lang.String"/>
</operation>
<operation name="removeUser"
description="Remove existing user (and all group memberships)"
impact="ACTION"
returnType="void">
<parameter name="username"
description="User name of the user to remove"
type="java.lang.String"/>
</operation>
<operation name="save"
description="Save current users and groups to persistent storage"
impact="ACTION"
returnType="void">
</operation>
</mbean>
</mbeans-descriptors>