From: Mathieu Baudier Date: Mon, 11 Mar 2024 07:59:54 +0000 (+0100) Subject: Refactor Argeo APIs X-Git-Tag: v2.3.28~10 X-Git-Url: http://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=40f2d6712d120dd62a42b7db3a6f074ce49c83d4 Refactor Argeo APIs --- diff --git a/Makefile b/Makefile index 407f4214b..497de15b0 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,6 @@ org.argeo.init \ org.argeo.api.uuid \ org.argeo.api.register \ org.argeo.api.acr \ -org.argeo.api.cli \ org.argeo.api.cms \ org.argeo.cms \ org.argeo.cms.ux \ diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapNameUtils.java b/org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapNameUtils.java new file mode 100644 index 000000000..72fa65ab0 --- /dev/null +++ b/org.argeo.api.acr/src/org/argeo/api/acr/ldap/LdapNameUtils.java @@ -0,0 +1,69 @@ +package org.argeo.api.acr.ldap; + +import javax.naming.InvalidNameException; +import javax.naming.ldap.LdapName; +import javax.naming.ldap.Rdn; + +/** Utilities to simplify using {@link LdapName}. */ +public class LdapNameUtils { + + public static LdapName relativeName(LdapName prefix, LdapName dn) { + try { + if (!dn.startsWith(prefix)) + throw new IllegalArgumentException("Prefix " + prefix + " not consistent with " + dn); + LdapName res = (LdapName) dn.clone(); + for (int i = 0; i < prefix.size(); i++) { + res.remove(0); + } + return res; + } catch (InvalidNameException e) { + throw new IllegalStateException("Cannot find realtive name", e); + } + } + + public static LdapName getParent(LdapName dn) { + try { + LdapName parent = (LdapName) dn.clone(); + parent.remove(parent.size() - 1); + return parent; + } catch (InvalidNameException e) { + throw new IllegalArgumentException("Cannot get parent of " + dn, e); + } + } + + public static Rdn getParentRdn(LdapName dn) { + if (dn.size() < 2) + throw new IllegalArgumentException(dn + " has no parent"); + Rdn parentRdn = dn.getRdn(dn.size() - 2); + return parentRdn; + } + + public static LdapName toLdapName(String distinguishedName) { + try { + return new LdapName(distinguishedName); + } catch (InvalidNameException e) { + throw new IllegalArgumentException("Cannot parse " + distinguishedName + " as LDAP name", e); + } + } + + public static Rdn getLastRdn(LdapName dn) { + return dn.getRdn(dn.size() - 1); + } + + public static String getLastRdnAsString(LdapName dn) { + return getLastRdn(dn).toString(); + } + + public static String getLastRdnValue(String dn) { + return getLastRdnValue(toLdapName(dn)); + } + + public static String getLastRdnValue(LdapName dn) { + return getLastRdn(dn).getValue().toString(); + } + + /** singleton */ + private LdapNameUtils() { + + } +} diff --git a/org.argeo.api.cli/.classpath b/org.argeo.api.cli/.classpath deleted file mode 100644 index 81fe078c2..000000000 --- a/org.argeo.api.cli/.classpath +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/org.argeo.api.cli/.project b/org.argeo.api.cli/.project deleted file mode 100644 index 8f5cd419b..000000000 --- a/org.argeo.api.cli/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - org.argeo.api.cli - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - - org.eclipse.pde.PluginNature - org.eclipse.jdt.core.javanature - - diff --git a/org.argeo.api.cli/bnd.bnd b/org.argeo.api.cli/bnd.bnd deleted file mode 100644 index e69de29bb..000000000 diff --git a/org.argeo.api.cli/build.properties b/org.argeo.api.cli/build.properties deleted file mode 100644 index 34d2e4d2d..000000000 --- a/org.argeo.api.cli/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -source.. = src/ -output.. = bin/ -bin.includes = META-INF/,\ - . diff --git a/org.argeo.api.cli/src/org/argeo/api/cli/CommandArgsException.java b/org.argeo.api.cli/src/org/argeo/api/cli/CommandArgsException.java deleted file mode 100644 index 935247fee..000000000 --- a/org.argeo.api.cli/src/org/argeo/api/cli/CommandArgsException.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.argeo.api.cli; - -/** Exception thrown when the provided arguments are not correct. */ -public class CommandArgsException extends IllegalArgumentException { - private static final long serialVersionUID = -7271050747105253935L; - private String commandName; - private volatile CommandsCli commandsCli; - - public CommandArgsException(Exception cause) { - super(cause.getMessage(), cause); - } - - public CommandArgsException(String message) { - super(message); - } - - public String getCommandName() { - return commandName; - } - - public void setCommandName(String commandName) { - this.commandName = commandName; - } - - public CommandsCli getCommandsCli() { - return commandsCli; - } - - public void setCommandsCli(CommandsCli commandsCli) { - this.commandsCli = commandsCli; - } - -} diff --git a/org.argeo.api.cli/src/org/argeo/api/cli/CommandRuntimeException.java b/org.argeo.api.cli/src/org/argeo/api/cli/CommandRuntimeException.java deleted file mode 100644 index 52c033433..000000000 --- a/org.argeo.api.cli/src/org/argeo/api/cli/CommandRuntimeException.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.argeo.api.cli; - -import java.util.List; - -/** {@link RuntimeException} referring during a command run. */ -public class CommandRuntimeException extends RuntimeException { - private static final long serialVersionUID = 5595999301269377128L; - - private final DescribedCommand command; - private final List arguments; - - public CommandRuntimeException(Throwable e, DescribedCommand command, List arguments) { - this(null, e, command, arguments); - } - - public CommandRuntimeException(String message, DescribedCommand command, List arguments) { - this(message, null, command, arguments); - } - - public CommandRuntimeException(String message, Throwable e, DescribedCommand command, List arguments) { - super(message == null ? "(" + command.getClass().getName() + " " + arguments.toString() + ")" - : message + " (" + command.getClass().getName() + " " + arguments.toString() + ")", e); - this.command = command; - this.arguments = arguments; - } - - public DescribedCommand getCommand() { - return command; - } - - public List getArguments() { - return arguments; - } - -} diff --git a/org.argeo.api.cli/src/org/argeo/api/cli/CommandsCli.java b/org.argeo.api.cli/src/org/argeo/api/cli/CommandsCli.java deleted file mode 100644 index 5bbfcfa07..000000000 --- a/org.argeo.api.cli/src/org/argeo/api/cli/CommandsCli.java +++ /dev/null @@ -1,157 +0,0 @@ -package org.argeo.api.cli; - -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.function.Function; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.MissingOptionException; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; - -/** Base class for a CLI managing sub commands. */ -public abstract class CommandsCli implements DescribedCommand { - private final String commandName; - private Map, ?>> commands = new TreeMap<>(); - - protected final Options options = new Options(); - - public CommandsCli(String commandName) { - this.commandName = commandName; - } - - @Override - public Object apply(List args) { - String cmd = null; - List newArgs = new ArrayList<>(); - boolean isHelpOption = false; - try { - CommandLineParser clParser = new DefaultParser(); - CommandLine commonCl = clParser.parse(getOptions(), args.toArray(new String[args.size()]), true); - List leftOvers = commonCl.getArgList(); - for (String arg : leftOvers) { - if (arg.equals("--" + HelpCommand.HELP_OPTION.getLongOpt())) { - isHelpOption = true; - // TODO break? - } - - if (!arg.startsWith("-") && cmd == null) { - cmd = arg; - } else { - newArgs.add(arg); - } - } - } catch (ParseException e) { - CommandArgsException cae = new CommandArgsException(e); - throw cae; - } - - Function, ?> function = cmd != null ? getCommand(cmd) : getDefaultCommand(); - - // --help option - if (!(function instanceof CommandsCli)) - if (function instanceof DescribedCommand command) - if (isHelpOption) { - throw new PrintHelpRequestException(cmd, this); -// StringWriter out = new StringWriter(); -// HelpCommand.printHelp(command, out); -// System.out.println(out.toString()); -// return null; - } - - if (function == null) - throw new IllegalArgumentException("Uknown command " + cmd); - try { - Object value = function.apply(newArgs); - return value != null ? value.toString() : null; - } catch (CommandArgsException e) { - if (e.getCommandName() == null) { - e.setCommandName(cmd); - e.setCommandsCli(this); - } - throw e; - } catch (IllegalArgumentException e) { - CommandArgsException cae = new CommandArgsException(e); - cae.setCommandName(cmd); - throw cae; - } - } - - @Override - public Options getOptions() { - return options; - } - - protected void addCommand(String cmd, Function, ?> function) { - commands.put(cmd, function); - - } - - @Override - public String getUsage() { - return "[command]"; - } - - protected void addCommandsCli(CommandsCli commandsCli) { - addCommand(commandsCli.getCommandName(), commandsCli); - commandsCli.addCommand(HelpCommand.HELP, new HelpCommand(this, commandsCli)); - } - - public String getCommandName() { - return commandName; - } - - public Set getSubCommands() { - return commands.keySet(); - } - - public Function, ?> getCommand(String command) { - return commands.get(command); - } - - public HelpCommand getHelpCommand() { - return (HelpCommand) getCommand(HelpCommand.HELP); - } - - public Function, String> getDefaultCommand() { - return getHelpCommand(); - } - - /** In order to implement quickly a main method. */ - public static void mainImpl(CommandsCli cli, String[] args) { - try { - cli.addCommand(HelpCommand.HELP, new HelpCommand(null, cli)); - Object output = cli.apply(Arrays.asList(args)); - if (output != null) - System.out.println(output); - System.exit(0); - } catch (PrintHelpRequestException e) { - StringWriter out = new StringWriter(); - HelpCommand.printHelp(e.getCommandsCli(), e.getCommandName(), out); - System.out.println(out.toString()); - } catch (CommandArgsException e) { - System.err.println("Wrong arguments " + Arrays.toString(args) + ": " + e.getMessage()); - Throwable cause = e.getCause(); - if (!(cause instanceof MissingOptionException)) - e.printStackTrace(); - if (e.getCommandName() != null) { - StringWriter out = new StringWriter(); - HelpCommand.printHelp(e.getCommandsCli(), e.getCommandName(), out); - System.err.println(out.toString()); - } else { - e.printStackTrace(); - } - System.exit(1); - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } - } -} diff --git a/org.argeo.api.cli/src/org/argeo/api/cli/DescribedCommand.java b/org.argeo.api.cli/src/org/argeo/api/cli/DescribedCommand.java deleted file mode 100644 index 51cb2ceca..000000000 --- a/org.argeo.api.cli/src/org/argeo/api/cli/DescribedCommand.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.argeo.api.cli; - -import java.io.StringWriter; -import java.util.Arrays; -import java.util.List; -import java.util.function.Function; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; - -/** A command that can be described. */ -public interface DescribedCommand extends Function, T> { - default Options getOptions() { - return new Options(); - } - - String getDescription(); - - default String getUsage() { - return null; - } - - default String getExamples() { - return null; - } - - default CommandLine toCommandLine(List args) { - try { - DefaultParser parser = new DefaultParser(); - return parser.parse(getOptions(), args.toArray(new String[args.size()])); - } catch (ParseException e) { - throw new CommandArgsException(e); - } - } - - /** In order to implement quickly a main method. */ - public static void mainImpl(DescribedCommand command, String[] args) { - try { - Object output = command.apply(Arrays.asList(args)); - System.out.println(output); - System.exit(0); - } catch (PrintHelpRequestException e) { - StringWriter out = new StringWriter(); - HelpCommand.printHelp(command, out); - System.out.println(out.toString()); - System.exit(1); - } catch (IllegalArgumentException e) { - StringWriter out = new StringWriter(); - HelpCommand.printHelp(command, out); - System.err.println(out.toString()); - System.exit(1); - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } - } - -} diff --git a/org.argeo.api.cli/src/org/argeo/api/cli/HelpCommand.java b/org.argeo.api.cli/src/org/argeo/api/cli/HelpCommand.java deleted file mode 100644 index cd51d7695..000000000 --- a/org.argeo.api.cli/src/org/argeo/api/cli/HelpCommand.java +++ /dev/null @@ -1,164 +0,0 @@ -package org.argeo.api.cli; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.List; -import java.util.function.Function; - -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; - -/** A special command that can describe {@link DescribedCommand}. */ -public class HelpCommand implements DescribedCommand { - /** - * System property forcing the root command to this value (typically the name of - * a script). - */ - public final static String ROOT_COMMAND_PROPERTY = "org.argeo.api.cli.rootCommand"; - - final static String HELP = "help"; - final static Option HELP_OPTION = Option.builder().longOpt(HELP).desc("print this help").build(); - - private CommandsCli commandsCli; - private CommandsCli parentCommandsCli; - - // Help formatting - private static int helpWidth = 80; - private static int helpLeftPad = 4; - private static int helpDescPad = 20; - - public HelpCommand(CommandsCli parentCommandsCli, CommandsCli commandsCli) { - super(); - this.parentCommandsCli = parentCommandsCli; - this.commandsCli = commandsCli; - } - - @Override - public String apply(List args) { - StringWriter out = new StringWriter(); - - if (args.size() == 0) {// overview - printHelp(commandsCli, out); - } else { - String cmd = args.get(0); - Function, ?> function = commandsCli.getCommand(cmd); - if (function == null) - return "Command " + cmd + " not found."; - Options options; - String examples; - DescribedCommand command = null; - if (function instanceof DescribedCommand) { - command = (DescribedCommand) function; - options = command.getOptions(); - examples = command.getExamples(); - } else { - options = new Options(); - examples = null; - } - String description = getShortDescription(function); - String commandCall = getCommandUsage(cmd, command); - HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp(new PrintWriter(out), helpWidth, commandCall, description, options, helpLeftPad, - helpDescPad, examples, false); - } - return out.toString(); - } - - private static String getShortDescription(Function, ?> function) { - if (function instanceof DescribedCommand) { - return ((DescribedCommand) function).getDescription(); - } else { - return function.toString(); - } - } - - public String getCommandUsage(String cmd, DescribedCommand command) { - String commandCall = getCommandCall(commandsCli) + " " + cmd; - assert command != null; - if (command != null && command.getUsage() != null) { - commandCall = commandCall + " " + command.getUsage(); - } - return commandCall; - } - - @Override - public String getDescription() { - return "Shows this help or describes a command"; - } - - @Override - public String getUsage() { - return "[command]"; - } - - public CommandsCli getParentCommandsCli() { - return parentCommandsCli; - } - - protected String getCommandCall(CommandsCli commandsCli) { - HelpCommand hc = commandsCli.getHelpCommand(); - if (hc.getParentCommandsCli() != null) { - return getCommandCall(hc.getParentCommandsCli()) + " " + commandsCli.getCommandName(); - } else { - String rootCommand = System.getProperty(ROOT_COMMAND_PROPERTY); - if (rootCommand != null) - return rootCommand; - return commandsCli.getCommandName(); - } - } - - public static void printHelp(DescribedCommand command, StringWriter out) { - String usage = "java " + command.getClass().getName() - + (command.getUsage() != null ? " " + command.getUsage() : ""); - HelpFormatter formatter = new HelpFormatter(); - Options options = command.getOptions(); - options.addOption(HelpCommand.HELP_OPTION); - formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), options, helpLeftPad, - helpDescPad, command.getExamples(), false); - - } - - public static void printHelp(CommandsCli commandsCli, String commandName, StringWriter out) { - if (commandName == null) { - printHelp(commandsCli, out); - return; - } - DescribedCommand command = (DescribedCommand) commandsCli.getCommand(commandName); - String usage = commandsCli.getHelpCommand().getCommandUsage(commandName, command); - HelpFormatter formatter = new HelpFormatter(); - Options options = command.getOptions(); - options.addOption(HelpCommand.HELP_OPTION); - formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), options, helpLeftPad, - helpDescPad, command.getExamples(), false); - - } - - public static void printHelp(CommandsCli commandsCli, StringWriter out) { - out.append(commandsCli.getDescription()).append('\n'); - String leftPad = spaces(helpLeftPad); - for (String cmd : commandsCli.getSubCommands()) { - Function, ?> function = commandsCli.getCommand(cmd); - assert function != null; - out.append(leftPad); - out.append(cmd); - // TODO deal with long commands - out.append(spaces(helpDescPad - cmd.length())); - out.append(getShortDescription(function)); - out.append('\n'); - } - } - - private static String spaces(int count) { - // Java 11 - // return " ".repeat(count); - if (count <= 0) - return ""; - else { - StringBuilder sb = new StringBuilder(count); - for (int i = 0; i < count; i++) - sb.append(' '); - return sb.toString(); - } - } -} diff --git a/org.argeo.api.cli/src/org/argeo/api/cli/PrintHelpRequestException.java b/org.argeo.api.cli/src/org/argeo/api/cli/PrintHelpRequestException.java deleted file mode 100644 index 017386b83..000000000 --- a/org.argeo.api.cli/src/org/argeo/api/cli/PrintHelpRequestException.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.argeo.api.cli; - -/** An exception indicating that help should be printed. */ -class PrintHelpRequestException extends RuntimeException { - - private static final long serialVersionUID = -9029122270660656639L; - - private String commandName; - private volatile CommandsCli commandsCli; - - public PrintHelpRequestException(String commandName, CommandsCli commandsCli) { - super(); - this.commandName = commandName; - this.commandsCli = commandsCli; - } - - public static long getSerialversionuid() { - return serialVersionUID; - } - - public String getCommandName() { - return commandName; - } - - public CommandsCli getCommandsCli() { - return commandsCli; - } - -} diff --git a/org.argeo.api.cli/src/org/argeo/api/cli/package-info.java b/org.argeo.api.cli/src/org/argeo/api/cli/package-info.java deleted file mode 100644 index 114fd02d4..000000000 --- a/org.argeo.api.cli/src/org/argeo/api/cli/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -/** Command line API. */ -package org.argeo.api.cli; \ No newline at end of file diff --git a/org.argeo.api.cms/META-INF/.gitignore b/org.argeo.api.cms/META-INF/.gitignore deleted file mode 100644 index 4854a41b9..000000000 --- a/org.argeo.api.cms/META-INF/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/MANIFEST.MF diff --git a/org.argeo.api.cms/bnd.bnd b/org.argeo.api.cms/bnd.bnd index 0b7c5a4da..19a9abdf2 100644 --- a/org.argeo.api.cms/bnd.bnd +++ b/org.argeo.api.cms/bnd.bnd @@ -1,7 +1,6 @@ Import-Package: \ javax.transaction.xa,\ javax.security.*,\ -org.osgi.service.useradmin,\ * Export-Package: org.argeo.api.cms.* \ No newline at end of file diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/auth/ImpliedByPrincipal.java b/org.argeo.api.cms/src/org/argeo/api/cms/auth/ImpliedByPrincipal.java new file mode 100644 index 000000000..21a632594 --- /dev/null +++ b/org.argeo.api.cms/src/org/argeo/api/cms/auth/ImpliedByPrincipal.java @@ -0,0 +1,72 @@ +package org.argeo.api.cms.auth; + +import java.security.Principal; +import java.util.HashSet; +import java.util.Set; + +import javax.xml.namespace.QName; + +/** + * A {@link Principal} which has been implied by an authorisation. If it is + * empty it means this is an additional identity, otherwise it lists the users + * (typically the logged-in user but possibly empty {@link ImpliedByPrincipal}s) + * which have implied it. When an additional identity is removed, the related + * {@link ImpliedByPrincipal}s can thus be removed. + */ +public final class ImpliedByPrincipal implements Principal { + private final String name; + private final QName roleName; + private final boolean systemRole; + private final String context; + + private Set causes = new HashSet(); + + public ImpliedByPrincipal(String name, Principal userPrincipal) { + this.name = name; + roleName = RoleNameUtils.getLastRdnAsName(name); + systemRole = RoleNameUtils.isSystemRole(roleName); + context = RoleNameUtils.getContext(name); + if (userPrincipal != null) + causes.add(userPrincipal); + } + + public String getName() { + return name; + } + + /* + * OBJECT + */ + + public QName getRoleName() { + return roleName; + } + + public String getContext() { + return context; + } + + public boolean isSystemRole() { + return systemRole; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ImpliedByPrincipal) { + ImpliedByPrincipal that = (ImpliedByPrincipal) obj; + // TODO check members too? + return name.equals(that.name); + } + return false; + } + + @Override + public String toString() { + return name.toString(); + } +} diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/auth/RoleNameUtils.java b/org.argeo.api.cms/src/org/argeo/api/cms/auth/RoleNameUtils.java new file mode 100644 index 000000000..52e238010 --- /dev/null +++ b/org.argeo.api.cms/src/org/argeo/api/cms/auth/RoleNameUtils.java @@ -0,0 +1,41 @@ +package org.argeo.api.cms.auth; + +import static org.argeo.api.acr.RuntimeNamespaceContext.getNamespaceContext; + +import javax.xml.namespace.QName; + +import org.argeo.api.acr.ArgeoNamespace; +import org.argeo.api.acr.NamespaceUtils; +import org.argeo.api.acr.ldap.LdapNameUtils; + +/** Simplifies analysis of system roles. */ +public class RoleNameUtils { + public static String getLastRdnValue(String dn) { + return LdapNameUtils.getLastRdnValue(dn); +// // we don't use LdapName for portability with Android +// // TODO make it more robust +// String[] parts = dn.split(","); +// String[] rdn = parts[0].split("="); +// return rdn[1]; + } + + public static QName getLastRdnAsName(String dn) { + String cn = getLastRdnValue(dn); + QName roleName = NamespaceUtils.parsePrefixedName(getNamespaceContext(), cn); + return roleName; + } + + public static boolean isSystemRole(QName roleName) { + return roleName.getNamespaceURI().equals(ArgeoNamespace.ROLE_NAMESPACE_URI); + } + + public static String getParent(String dn) { + int index = dn.indexOf(','); + return dn.substring(index + 1); + } + + /** Up two levels. */ + public static String getContext(String dn) { + return getParent(getParent(dn)); + } +} diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/auth/SystemRole.java b/org.argeo.api.cms/src/org/argeo/api/cms/auth/SystemRole.java new file mode 100644 index 000000000..988085178 --- /dev/null +++ b/org.argeo.api.cms/src/org/argeo/api/cms/auth/SystemRole.java @@ -0,0 +1,47 @@ +package org.argeo.api.cms.auth; + +import java.util.Set; + +import javax.security.auth.Subject; +import javax.xml.namespace.QName; + +import org.argeo.api.cms.CmsConstants; + +/** A programmatic role. */ +public interface SystemRole { + QName qName(); + + /** Whether this role is implied for this authenticated user. */ + default boolean implied(Subject subject, String context) { + return implied(qName(), subject, context); + } + + /** Whether this role is implied for this distinguished name. */ + default boolean implied(String dn, String context) { + String roleContext = RoleNameUtils.getContext(dn); + QName roleName = RoleNameUtils.getLastRdnAsName(dn); + return roleContext.equalsIgnoreCase(context) && qName().equals(roleName); + } + + /** + * Whether this role is implied for this authenticated subject. If context is + * null, it is not considered; this should be used to build user + * interfaces, but not to authorise. + */ + static boolean implied(QName name, Subject subject, String context) { + Set roles = subject.getPrincipals(ImpliedByPrincipal.class); + for (ImpliedByPrincipal role : roles) { + if (role.isSystemRole()) { + if (role.getRoleName().equals(name)) { + // !! if context is not specified, it is considered irrelevant + if (context == null) + return true; + if (role.getContext().equalsIgnoreCase(context) + || role.getContext().equals(CmsConstants.NODE_BASEDN)) + return true; + } + } + } + return false; + } +} diff --git a/org.argeo.cms/src/org/argeo/api/cli/CommandArgsException.java b/org.argeo.cms/src/org/argeo/api/cli/CommandArgsException.java new file mode 100644 index 000000000..935247fee --- /dev/null +++ b/org.argeo.cms/src/org/argeo/api/cli/CommandArgsException.java @@ -0,0 +1,33 @@ +package org.argeo.api.cli; + +/** Exception thrown when the provided arguments are not correct. */ +public class CommandArgsException extends IllegalArgumentException { + private static final long serialVersionUID = -7271050747105253935L; + private String commandName; + private volatile CommandsCli commandsCli; + + public CommandArgsException(Exception cause) { + super(cause.getMessage(), cause); + } + + public CommandArgsException(String message) { + super(message); + } + + public String getCommandName() { + return commandName; + } + + public void setCommandName(String commandName) { + this.commandName = commandName; + } + + public CommandsCli getCommandsCli() { + return commandsCli; + } + + public void setCommandsCli(CommandsCli commandsCli) { + this.commandsCli = commandsCli; + } + +} diff --git a/org.argeo.cms/src/org/argeo/api/cli/CommandRuntimeException.java b/org.argeo.cms/src/org/argeo/api/cli/CommandRuntimeException.java new file mode 100644 index 000000000..52c033433 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/api/cli/CommandRuntimeException.java @@ -0,0 +1,35 @@ +package org.argeo.api.cli; + +import java.util.List; + +/** {@link RuntimeException} referring during a command run. */ +public class CommandRuntimeException extends RuntimeException { + private static final long serialVersionUID = 5595999301269377128L; + + private final DescribedCommand command; + private final List arguments; + + public CommandRuntimeException(Throwable e, DescribedCommand command, List arguments) { + this(null, e, command, arguments); + } + + public CommandRuntimeException(String message, DescribedCommand command, List arguments) { + this(message, null, command, arguments); + } + + public CommandRuntimeException(String message, Throwable e, DescribedCommand command, List arguments) { + super(message == null ? "(" + command.getClass().getName() + " " + arguments.toString() + ")" + : message + " (" + command.getClass().getName() + " " + arguments.toString() + ")", e); + this.command = command; + this.arguments = arguments; + } + + public DescribedCommand getCommand() { + return command; + } + + public List getArguments() { + return arguments; + } + +} diff --git a/org.argeo.cms/src/org/argeo/api/cli/CommandsCli.java b/org.argeo.cms/src/org/argeo/api/cli/CommandsCli.java new file mode 100644 index 000000000..5bbfcfa07 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/api/cli/CommandsCli.java @@ -0,0 +1,157 @@ +package org.argeo.api.cli; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.function.Function; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.MissingOptionException; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +/** Base class for a CLI managing sub commands. */ +public abstract class CommandsCli implements DescribedCommand { + private final String commandName; + private Map, ?>> commands = new TreeMap<>(); + + protected final Options options = new Options(); + + public CommandsCli(String commandName) { + this.commandName = commandName; + } + + @Override + public Object apply(List args) { + String cmd = null; + List newArgs = new ArrayList<>(); + boolean isHelpOption = false; + try { + CommandLineParser clParser = new DefaultParser(); + CommandLine commonCl = clParser.parse(getOptions(), args.toArray(new String[args.size()]), true); + List leftOvers = commonCl.getArgList(); + for (String arg : leftOvers) { + if (arg.equals("--" + HelpCommand.HELP_OPTION.getLongOpt())) { + isHelpOption = true; + // TODO break? + } + + if (!arg.startsWith("-") && cmd == null) { + cmd = arg; + } else { + newArgs.add(arg); + } + } + } catch (ParseException e) { + CommandArgsException cae = new CommandArgsException(e); + throw cae; + } + + Function, ?> function = cmd != null ? getCommand(cmd) : getDefaultCommand(); + + // --help option + if (!(function instanceof CommandsCli)) + if (function instanceof DescribedCommand command) + if (isHelpOption) { + throw new PrintHelpRequestException(cmd, this); +// StringWriter out = new StringWriter(); +// HelpCommand.printHelp(command, out); +// System.out.println(out.toString()); +// return null; + } + + if (function == null) + throw new IllegalArgumentException("Uknown command " + cmd); + try { + Object value = function.apply(newArgs); + return value != null ? value.toString() : null; + } catch (CommandArgsException e) { + if (e.getCommandName() == null) { + e.setCommandName(cmd); + e.setCommandsCli(this); + } + throw e; + } catch (IllegalArgumentException e) { + CommandArgsException cae = new CommandArgsException(e); + cae.setCommandName(cmd); + throw cae; + } + } + + @Override + public Options getOptions() { + return options; + } + + protected void addCommand(String cmd, Function, ?> function) { + commands.put(cmd, function); + + } + + @Override + public String getUsage() { + return "[command]"; + } + + protected void addCommandsCli(CommandsCli commandsCli) { + addCommand(commandsCli.getCommandName(), commandsCli); + commandsCli.addCommand(HelpCommand.HELP, new HelpCommand(this, commandsCli)); + } + + public String getCommandName() { + return commandName; + } + + public Set getSubCommands() { + return commands.keySet(); + } + + public Function, ?> getCommand(String command) { + return commands.get(command); + } + + public HelpCommand getHelpCommand() { + return (HelpCommand) getCommand(HelpCommand.HELP); + } + + public Function, String> getDefaultCommand() { + return getHelpCommand(); + } + + /** In order to implement quickly a main method. */ + public static void mainImpl(CommandsCli cli, String[] args) { + try { + cli.addCommand(HelpCommand.HELP, new HelpCommand(null, cli)); + Object output = cli.apply(Arrays.asList(args)); + if (output != null) + System.out.println(output); + System.exit(0); + } catch (PrintHelpRequestException e) { + StringWriter out = new StringWriter(); + HelpCommand.printHelp(e.getCommandsCli(), e.getCommandName(), out); + System.out.println(out.toString()); + } catch (CommandArgsException e) { + System.err.println("Wrong arguments " + Arrays.toString(args) + ": " + e.getMessage()); + Throwable cause = e.getCause(); + if (!(cause instanceof MissingOptionException)) + e.printStackTrace(); + if (e.getCommandName() != null) { + StringWriter out = new StringWriter(); + HelpCommand.printHelp(e.getCommandsCli(), e.getCommandName(), out); + System.err.println(out.toString()); + } else { + e.printStackTrace(); + } + System.exit(1); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } +} diff --git a/org.argeo.cms/src/org/argeo/api/cli/DescribedCommand.java b/org.argeo.cms/src/org/argeo/api/cli/DescribedCommand.java new file mode 100644 index 000000000..51cb2ceca --- /dev/null +++ b/org.argeo.cms/src/org/argeo/api/cli/DescribedCommand.java @@ -0,0 +1,60 @@ +package org.argeo.api.cli; + +import java.io.StringWriter; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +/** A command that can be described. */ +public interface DescribedCommand extends Function, T> { + default Options getOptions() { + return new Options(); + } + + String getDescription(); + + default String getUsage() { + return null; + } + + default String getExamples() { + return null; + } + + default CommandLine toCommandLine(List args) { + try { + DefaultParser parser = new DefaultParser(); + return parser.parse(getOptions(), args.toArray(new String[args.size()])); + } catch (ParseException e) { + throw new CommandArgsException(e); + } + } + + /** In order to implement quickly a main method. */ + public static void mainImpl(DescribedCommand command, String[] args) { + try { + Object output = command.apply(Arrays.asList(args)); + System.out.println(output); + System.exit(0); + } catch (PrintHelpRequestException e) { + StringWriter out = new StringWriter(); + HelpCommand.printHelp(command, out); + System.out.println(out.toString()); + System.exit(1); + } catch (IllegalArgumentException e) { + StringWriter out = new StringWriter(); + HelpCommand.printHelp(command, out); + System.err.println(out.toString()); + System.exit(1); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + +} diff --git a/org.argeo.cms/src/org/argeo/api/cli/HelpCommand.java b/org.argeo.cms/src/org/argeo/api/cli/HelpCommand.java new file mode 100644 index 000000000..cd51d7695 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/api/cli/HelpCommand.java @@ -0,0 +1,164 @@ +package org.argeo.api.cli; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.List; +import java.util.function.Function; + +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; + +/** A special command that can describe {@link DescribedCommand}. */ +public class HelpCommand implements DescribedCommand { + /** + * System property forcing the root command to this value (typically the name of + * a script). + */ + public final static String ROOT_COMMAND_PROPERTY = "org.argeo.api.cli.rootCommand"; + + final static String HELP = "help"; + final static Option HELP_OPTION = Option.builder().longOpt(HELP).desc("print this help").build(); + + private CommandsCli commandsCli; + private CommandsCli parentCommandsCli; + + // Help formatting + private static int helpWidth = 80; + private static int helpLeftPad = 4; + private static int helpDescPad = 20; + + public HelpCommand(CommandsCli parentCommandsCli, CommandsCli commandsCli) { + super(); + this.parentCommandsCli = parentCommandsCli; + this.commandsCli = commandsCli; + } + + @Override + public String apply(List args) { + StringWriter out = new StringWriter(); + + if (args.size() == 0) {// overview + printHelp(commandsCli, out); + } else { + String cmd = args.get(0); + Function, ?> function = commandsCli.getCommand(cmd); + if (function == null) + return "Command " + cmd + " not found."; + Options options; + String examples; + DescribedCommand command = null; + if (function instanceof DescribedCommand) { + command = (DescribedCommand) function; + options = command.getOptions(); + examples = command.getExamples(); + } else { + options = new Options(); + examples = null; + } + String description = getShortDescription(function); + String commandCall = getCommandUsage(cmd, command); + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp(new PrintWriter(out), helpWidth, commandCall, description, options, helpLeftPad, + helpDescPad, examples, false); + } + return out.toString(); + } + + private static String getShortDescription(Function, ?> function) { + if (function instanceof DescribedCommand) { + return ((DescribedCommand) function).getDescription(); + } else { + return function.toString(); + } + } + + public String getCommandUsage(String cmd, DescribedCommand command) { + String commandCall = getCommandCall(commandsCli) + " " + cmd; + assert command != null; + if (command != null && command.getUsage() != null) { + commandCall = commandCall + " " + command.getUsage(); + } + return commandCall; + } + + @Override + public String getDescription() { + return "Shows this help or describes a command"; + } + + @Override + public String getUsage() { + return "[command]"; + } + + public CommandsCli getParentCommandsCli() { + return parentCommandsCli; + } + + protected String getCommandCall(CommandsCli commandsCli) { + HelpCommand hc = commandsCli.getHelpCommand(); + if (hc.getParentCommandsCli() != null) { + return getCommandCall(hc.getParentCommandsCli()) + " " + commandsCli.getCommandName(); + } else { + String rootCommand = System.getProperty(ROOT_COMMAND_PROPERTY); + if (rootCommand != null) + return rootCommand; + return commandsCli.getCommandName(); + } + } + + public static void printHelp(DescribedCommand command, StringWriter out) { + String usage = "java " + command.getClass().getName() + + (command.getUsage() != null ? " " + command.getUsage() : ""); + HelpFormatter formatter = new HelpFormatter(); + Options options = command.getOptions(); + options.addOption(HelpCommand.HELP_OPTION); + formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), options, helpLeftPad, + helpDescPad, command.getExamples(), false); + + } + + public static void printHelp(CommandsCli commandsCli, String commandName, StringWriter out) { + if (commandName == null) { + printHelp(commandsCli, out); + return; + } + DescribedCommand command = (DescribedCommand) commandsCli.getCommand(commandName); + String usage = commandsCli.getHelpCommand().getCommandUsage(commandName, command); + HelpFormatter formatter = new HelpFormatter(); + Options options = command.getOptions(); + options.addOption(HelpCommand.HELP_OPTION); + formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), options, helpLeftPad, + helpDescPad, command.getExamples(), false); + + } + + public static void printHelp(CommandsCli commandsCli, StringWriter out) { + out.append(commandsCli.getDescription()).append('\n'); + String leftPad = spaces(helpLeftPad); + for (String cmd : commandsCli.getSubCommands()) { + Function, ?> function = commandsCli.getCommand(cmd); + assert function != null; + out.append(leftPad); + out.append(cmd); + // TODO deal with long commands + out.append(spaces(helpDescPad - cmd.length())); + out.append(getShortDescription(function)); + out.append('\n'); + } + } + + private static String spaces(int count) { + // Java 11 + // return " ".repeat(count); + if (count <= 0) + return ""; + else { + StringBuilder sb = new StringBuilder(count); + for (int i = 0; i < count; i++) + sb.append(' '); + return sb.toString(); + } + } +} diff --git a/org.argeo.cms/src/org/argeo/api/cli/PrintHelpRequestException.java b/org.argeo.cms/src/org/argeo/api/cli/PrintHelpRequestException.java new file mode 100644 index 000000000..017386b83 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/api/cli/PrintHelpRequestException.java @@ -0,0 +1,29 @@ +package org.argeo.api.cli; + +/** An exception indicating that help should be printed. */ +class PrintHelpRequestException extends RuntimeException { + + private static final long serialVersionUID = -9029122270660656639L; + + private String commandName; + private volatile CommandsCli commandsCli; + + public PrintHelpRequestException(String commandName, CommandsCli commandsCli) { + super(); + this.commandName = commandName; + this.commandsCli = commandsCli; + } + + public static long getSerialversionuid() { + return serialVersionUID; + } + + public String getCommandName() { + return commandName; + } + + public CommandsCli getCommandsCli() { + return commandsCli; + } + +} diff --git a/org.argeo.cms/src/org/argeo/api/cli/package-info.java b/org.argeo.cms/src/org/argeo/api/cli/package-info.java new file mode 100644 index 000000000..114fd02d4 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/api/cli/package-info.java @@ -0,0 +1,2 @@ +/** Command line API. */ +package org.argeo.api.cli; \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/CurrentUser.java b/org.argeo.cms/src/org/argeo/cms/CurrentUser.java index ad12a8665..c879a4d2d 100644 --- a/org.argeo.cms/src/org/argeo/cms/CurrentUser.java +++ b/org.argeo.cms/src/org/argeo/cms/CurrentUser.java @@ -17,8 +17,10 @@ import org.argeo.api.acr.NamespaceUtils; import org.argeo.api.cms.CmsConstants; import org.argeo.api.cms.CmsSession; import org.argeo.api.cms.CmsSessionId; +import org.argeo.api.cms.auth.ImpliedByPrincipal; +import org.argeo.api.cms.auth.RoleNameUtils; +import org.argeo.api.cms.auth.SystemRole; import org.argeo.cms.internal.auth.CmsSessionImpl; -import org.argeo.cms.internal.auth.ImpliedByPrincipal; import org.argeo.cms.internal.runtime.CmsContextImpl; import org.argeo.cms.util.CurrentSubject; import org.osgi.service.useradmin.Authorization; diff --git a/org.argeo.cms/src/org/argeo/cms/RoleNameUtils.java b/org.argeo.cms/src/org/argeo/cms/RoleNameUtils.java deleted file mode 100644 index 04302c42f..000000000 --- a/org.argeo.cms/src/org/argeo/cms/RoleNameUtils.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.argeo.cms; - -import static org.argeo.api.acr.RuntimeNamespaceContext.getNamespaceContext; - -import javax.xml.namespace.QName; - -import org.argeo.api.acr.ArgeoNamespace; -import org.argeo.api.acr.NamespaceUtils; -import org.argeo.cms.directory.ldap.LdapNameUtils; - -/** Simplifies analysis of system roles. */ -public class RoleNameUtils { - public static String getLastRdnValue(String dn) { - return LdapNameUtils.getLastRdnValue(dn); -// // we don't use LdapName for portability with Android -// // TODO make it more robust -// String[] parts = dn.split(","); -// String[] rdn = parts[0].split("="); -// return rdn[1]; - } - - public static QName getLastRdnAsName(String dn) { - String cn = getLastRdnValue(dn); - QName roleName = NamespaceUtils.parsePrefixedName(getNamespaceContext(), cn); - return roleName; - } - - public static boolean isSystemRole(QName roleName) { - return roleName.getNamespaceURI().equals(ArgeoNamespace.ROLE_NAMESPACE_URI); - } - - public static String getParent(String dn) { - int index = dn.indexOf(','); - return dn.substring(index + 1); - } - - /** Up two levels. */ - public static String getContext(String dn) { - return getParent(getParent(dn)); - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/SystemRole.java b/org.argeo.cms/src/org/argeo/cms/SystemRole.java deleted file mode 100644 index 95643998a..000000000 --- a/org.argeo.cms/src/org/argeo/cms/SystemRole.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.argeo.cms; - -import java.util.Set; - -import javax.security.auth.Subject; -import javax.xml.namespace.QName; - -import org.argeo.api.cms.CmsConstants; -import org.argeo.cms.internal.auth.ImpliedByPrincipal; - -/** A programmatic role. */ -public interface SystemRole { - QName qName(); - - /** Whether this role is implied for this authenticated user. */ - default boolean implied(Subject subject, String context) { - return implied(qName(), subject, context); - } - - /** Whether this role is implied for this distinguished name. */ - default boolean implied(String dn, String context) { - String roleContext = RoleNameUtils.getContext(dn); - QName roleName = RoleNameUtils.getLastRdnAsName(dn); - return roleContext.equalsIgnoreCase(context) && qName().equals(roleName); - } - - /** - * Whether this role is implied for this authenticated subject. If context is - * null, it is not considered; this should be used to build user - * interfaces, but not to authorise. - */ - static boolean implied(QName name, Subject subject, String context) { - Set roles = subject.getPrincipals(ImpliedByPrincipal.class); - for (ImpliedByPrincipal role : roles) { - if (role.isSystemRole()) { - if (role.getRoleName().equals(name)) { - // !! if context is not specified, it is considered irrelevant - if (context == null) - return true; - if (role.getContext().equalsIgnoreCase(context) - || role.getContext().equals(CmsConstants.NODE_BASEDN)) - return true; - } - } - } - return false; - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java b/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java index 379920724..6657e794e 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java @@ -23,8 +23,8 @@ import org.argeo.api.cms.CmsConstants; import org.argeo.api.cms.CmsSession; import org.argeo.api.cms.CmsSessionId; import org.argeo.api.cms.DataAdminPrincipal; +import org.argeo.api.cms.auth.ImpliedByPrincipal; import org.argeo.cms.internal.auth.CmsSessionImpl; -import org.argeo.cms.internal.auth.ImpliedByPrincipal; import org.argeo.cms.internal.auth.RemoteCmsSessionImpl; import org.argeo.cms.internal.runtime.CmsContextImpl; import org.argeo.cms.osgi.useradmin.AuthenticatingUser; diff --git a/org.argeo.cms/src/org/argeo/cms/auth/CmsSystemRole.java b/org.argeo.cms/src/org/argeo/cms/auth/CmsSystemRole.java index 64dbd0f6e..87daa2f95 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/CmsSystemRole.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/CmsSystemRole.java @@ -4,7 +4,7 @@ import javax.xml.namespace.QName; import org.argeo.api.acr.ArgeoNamespace; import org.argeo.api.acr.ContentName; -import org.argeo.cms.SystemRole; +import org.argeo.api.cms.auth.SystemRole; /** Standard CMS system roles. */ public enum CmsSystemRole implements SystemRole { diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/AbstractLdapDirectory.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/AbstractLdapDirectory.java index 5dffcb63a..39355c3c4 100644 --- a/org.argeo.cms/src/org/argeo/cms/directory/ldap/AbstractLdapDirectory.java +++ b/org.argeo.cms/src/org/argeo/cms/directory/ldap/AbstractLdapDirectory.java @@ -1,6 +1,6 @@ package org.argeo.cms.directory.ldap; -import static org.argeo.cms.directory.ldap.LdapNameUtils.toLdapName; +import static org.argeo.api.acr.ldap.LdapNameUtils.toLdapName; import java.io.File; import java.net.URI; @@ -27,6 +27,7 @@ import javax.naming.ldap.Rdn; import javax.transaction.xa.XAResource; import org.argeo.api.acr.ldap.LdapAttr; +import org.argeo.api.acr.ldap.LdapNameUtils; import org.argeo.api.acr.ldap.LdapObj; import org.argeo.api.cms.directory.CmsDirectory; import org.argeo.api.cms.directory.HierarchyUnit; diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapDao.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapDao.java index cdc1c9fe6..ff785638d 100644 --- a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapDao.java +++ b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapDao.java @@ -20,6 +20,7 @@ import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; import org.argeo.api.acr.ldap.LdapAttr; +import org.argeo.api.acr.ldap.LdapNameUtils; import org.argeo.api.acr.ldap.LdapObj; import org.argeo.api.cms.directory.HierarchyUnit; diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapHierarchyUnit.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapHierarchyUnit.java index b60ee0c68..81b20f0a3 100644 --- a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapHierarchyUnit.java +++ b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapHierarchyUnit.java @@ -5,6 +5,7 @@ import java.util.Locale; import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; +import org.argeo.api.acr.ldap.LdapNameUtils; import org.argeo.api.cms.directory.HierarchyUnit; /** LDIF/LDAP based implementation of {@link HierarchyUnit}. */ diff --git a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapNameUtils.java b/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapNameUtils.java deleted file mode 100644 index 74f23da67..000000000 --- a/org.argeo.cms/src/org/argeo/cms/directory/ldap/LdapNameUtils.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.argeo.cms.directory.ldap; - -import javax.naming.InvalidNameException; -import javax.naming.ldap.LdapName; -import javax.naming.ldap.Rdn; - -/** Utilities to simplify using {@link LdapName}. */ -public class LdapNameUtils { - - public static LdapName relativeName(LdapName prefix, LdapName dn) { - try { - if (!dn.startsWith(prefix)) - throw new IllegalArgumentException("Prefix " + prefix + " not consistent with " + dn); - LdapName res = (LdapName) dn.clone(); - for (int i = 0; i < prefix.size(); i++) { - res.remove(0); - } - return res; - } catch (InvalidNameException e) { - throw new IllegalStateException("Cannot find realtive name", e); - } - } - - public static LdapName getParent(LdapName dn) { - try { - LdapName parent = (LdapName) dn.clone(); - parent.remove(parent.size() - 1); - return parent; - } catch (InvalidNameException e) { - throw new IllegalArgumentException("Cannot get parent of " + dn, e); - } - } - - public static Rdn getParentRdn(LdapName dn) { - if (dn.size() < 2) - throw new IllegalArgumentException(dn + " has no parent"); - Rdn parentRdn = dn.getRdn(dn.size() - 2); - return parentRdn; - } - - public static LdapName toLdapName(String distinguishedName) { - try { - return new LdapName(distinguishedName); - } catch (InvalidNameException e) { - throw new IllegalArgumentException("Cannot parse " + distinguishedName + " as LDAP name", e); - } - } - - public static Rdn getLastRdn(LdapName dn) { - return dn.getRdn(dn.size() - 1); - } - - public static String getLastRdnAsString(LdapName dn) { - return getLastRdn(dn).toString(); - } - - public static String getLastRdnValue(String dn) { - return getLastRdnValue(toLdapName(dn)); - } - - public static String getLastRdnValue(LdapName dn) { - return getLastRdn(dn).getValue().toString(); - } - - /** singleton */ - private LdapNameUtils() { - - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/ImpliedByPrincipal.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/ImpliedByPrincipal.java deleted file mode 100644 index 9e0ebce97..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/ImpliedByPrincipal.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.argeo.cms.internal.auth; - -import java.security.Principal; -import java.util.HashSet; -import java.util.Set; - -import javax.xml.namespace.QName; - -import org.argeo.cms.RoleNameUtils; -import org.osgi.service.useradmin.Authorization; - -/** - * A {@link Principal} which has been implied by an {@link Authorization}. If it - * is empty it means this is an additional identity, otherwise it lists the - * users (typically the logged in user but possibly empty - * {@link ImpliedByPrincipal}s) which have implied it. When an additional - * identity is removed, the related {@link ImpliedByPrincipal}s can thus be - * removed. - */ -public final class ImpliedByPrincipal implements Principal { - private final String name; - private final QName roleName; - private final boolean systemRole; - private final String context; - - private Set causes = new HashSet(); - - public ImpliedByPrincipal(String name, Principal userPrincipal) { - this.name = name; - roleName = RoleNameUtils.getLastRdnAsName(name); - systemRole = RoleNameUtils.isSystemRole(roleName); - context = RoleNameUtils.getContext(name); - if (userPrincipal != null) - causes.add(userPrincipal); - } - - public String getName() { - return name; - } - - /* - * OBJECT - */ - - public QName getRoleName() { - return roleName; - } - - public String getContext() { - return context; - } - - public boolean isSystemRole() { - return systemRole; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ImpliedByPrincipal) { - ImpliedByPrincipal that = (ImpliedByPrincipal) obj; - // TODO check members too? - return name.equals(that.name); - } - return false; - } - - @Override - public String toString() { - return name.toString(); - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/DirectoryUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/DirectoryUserAdmin.java index e5fb01242..47cf5d378 100644 --- a/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/DirectoryUserAdmin.java +++ b/org.argeo.cms/src/org/argeo/cms/osgi/useradmin/DirectoryUserAdmin.java @@ -25,6 +25,7 @@ import javax.naming.ldap.Rdn; import javax.security.auth.Subject; import javax.security.auth.kerberos.KerberosTicket; +import org.argeo.api.acr.ldap.LdapNameUtils; import org.argeo.api.cms.directory.CmsRole; import org.argeo.api.cms.directory.DirectoryDigestUtils; import org.argeo.api.cms.directory.HierarchyUnit; @@ -33,7 +34,6 @@ import org.argeo.cms.directory.ldap.AbstractLdapDirectory; import org.argeo.cms.directory.ldap.LdapDao; import org.argeo.cms.directory.ldap.LdapEntry; import org.argeo.cms.directory.ldap.LdapEntryWorkingCopy; -import org.argeo.cms.directory.ldap.LdapNameUtils; import org.argeo.cms.directory.ldap.LdifDao; import org.argeo.cms.runtime.DirectoryConf; import org.argeo.cms.util.CurrentSubject;