mirror of https://github.com/apache/cassandra
201 lines
8.6 KiB
Java
201 lines
8.6 KiB
Java
/*
|
|
* 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.cassandra.auth;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
|
|
import org.apache.cassandra.config.DatabaseDescriptor;
|
|
import org.apache.cassandra.exceptions.InvalidRequestException;
|
|
import org.apache.cassandra.exceptions.SyntaxException;
|
|
import org.apache.cassandra.utils.FBUtilities;
|
|
import org.mindrot.jbcrypt.BCrypt;
|
|
|
|
public class RoleOptions
|
|
{
|
|
private final Map<IRoleManager.Option, Object> options = new HashMap<>();
|
|
|
|
/**
|
|
* Set a value for a specific option.
|
|
* Throws SyntaxException if the same option is set multiple times
|
|
* @param option
|
|
* @param value
|
|
*/
|
|
public void setOption(IRoleManager.Option option, Object value)
|
|
{
|
|
if (options.containsKey(option))
|
|
throw new SyntaxException(String.format("Multiple definition for property '%s'", option.name()));
|
|
options.put(option, value);
|
|
}
|
|
|
|
/**
|
|
* Return true if there are no options with values set, false otherwise
|
|
* @return whether any options have values set or not
|
|
*/
|
|
public boolean isEmpty()
|
|
{
|
|
return options.isEmpty();
|
|
}
|
|
|
|
/**
|
|
* Return a map of all the options which have been set
|
|
* @return all options with values
|
|
*/
|
|
public Map<IRoleManager.Option, Object> getOptions()
|
|
{
|
|
return options;
|
|
}
|
|
|
|
/**
|
|
* Return a boolean value of the superuser option
|
|
* @return superuser option value
|
|
*/
|
|
public Optional<Boolean> getSuperuser()
|
|
{
|
|
return Optional.ofNullable((Boolean) options.get(IRoleManager.Option.SUPERUSER));
|
|
}
|
|
|
|
/**
|
|
* Return a boolean value of the login option
|
|
* @return login option value
|
|
*/
|
|
public Optional<Boolean> getLogin()
|
|
{
|
|
return Optional.ofNullable((Boolean) options.get(IRoleManager.Option.LOGIN));
|
|
}
|
|
|
|
/**
|
|
* Return the string value of the password option
|
|
* @return password option value
|
|
*/
|
|
public Optional<String> getPassword()
|
|
{
|
|
return Optional.ofNullable((String)options.get(IRoleManager.Option.PASSWORD));
|
|
}
|
|
|
|
public boolean isGeneratedPassword()
|
|
{
|
|
return (Boolean) options.getOrDefault(IRoleManager.Option.GENERATED_PASSWORD, Boolean.FALSE);
|
|
}
|
|
|
|
public boolean isGeneratedName()
|
|
{
|
|
return (Boolean) options.getOrDefault(IRoleManager.Option.GENERATED_NAME, Boolean.FALSE);
|
|
}
|
|
|
|
/**
|
|
* Return the string value of the hashed password option.
|
|
* @return hashed password option value
|
|
*/
|
|
public Optional<String> getHashedPassword()
|
|
{
|
|
return Optional.ofNullable((String) options.get(IRoleManager.Option.HASHED_PASSWORD));
|
|
}
|
|
|
|
/**
|
|
* Return a {@code Map<String, String>} representing custom options
|
|
* It is the responsiblity of IRoleManager implementations which support
|
|
* IRoleManager.Option.OPTION to handle type checking and conversion of these
|
|
* values, if present
|
|
* @return map of custom options
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public Optional<Map<String, String>> getCustomOptions()
|
|
{
|
|
return Optional.ofNullable((Map<String, String>) options.get(IRoleManager.Option.OPTIONS));
|
|
}
|
|
|
|
/**
|
|
* Validate the contents of the options in two ways:
|
|
* - Ensure that only a subset of the options supported by the configured IRoleManager are set
|
|
* - Validate the type of any option values present.
|
|
* Should either condition fail, then InvalidRequestException is thrown. This method is called
|
|
* during validation of CQL statements, so the IRE results in a error response to the client.
|
|
*
|
|
* @throws InvalidRequestException if any options which are not supported by the configured IRoleManager
|
|
* are set or if any option value is of an incorrect type.
|
|
*/
|
|
public void validate()
|
|
{
|
|
for (Map.Entry<IRoleManager.Option, Object> option : options.entrySet())
|
|
{
|
|
if (!DatabaseDescriptor.getRoleManager().supportedOptions().contains(option.getKey()))
|
|
throw new InvalidRequestException(String.format("%s doesn't support %s",
|
|
DatabaseDescriptor.getRoleManager().getClass().getName(),
|
|
option.getKey()));
|
|
switch (option.getKey())
|
|
{
|
|
case LOGIN:
|
|
case SUPERUSER:
|
|
if (!(option.getValue() instanceof Boolean))
|
|
throw new InvalidRequestException(String.format("Invalid value for property '%s'. " +
|
|
"It must be a boolean",
|
|
option.getKey()));
|
|
break;
|
|
case PASSWORD:
|
|
if (!(option.getValue() instanceof String))
|
|
throw new InvalidRequestException(String.format("Invalid value for property '%s'. " +
|
|
"It must be a string",
|
|
option.getKey()));
|
|
if (options.containsKey(IRoleManager.Option.HASHED_PASSWORD))
|
|
throw new InvalidRequestException(String.format("Properties '%s' and '%s' are mutually exclusive",
|
|
IRoleManager.Option.PASSWORD, IRoleManager.Option.HASHED_PASSWORD));
|
|
break;
|
|
case HASHED_PASSWORD:
|
|
if (!(option.getValue() instanceof String))
|
|
throw new InvalidRequestException(String.format("Invalid value for property '%s'. " +
|
|
"It must be a string",
|
|
option.getKey()));
|
|
if (options.containsKey(IRoleManager.Option.PASSWORD))
|
|
throw new InvalidRequestException(String.format("Properties '%s' and '%s' are mutually exclusive",
|
|
IRoleManager.Option.PASSWORD, IRoleManager.Option.HASHED_PASSWORD));
|
|
try
|
|
{
|
|
BCrypt.checkpw("dummy", (String) option.getValue());
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
throw new InvalidRequestException("Invalid hashed password value. Please use jBcrypt.");
|
|
}
|
|
break;
|
|
case GENERATED_PASSWORD:
|
|
if (options.containsKey(IRoleManager.Option.PASSWORD))
|
|
throw new InvalidRequestException(String.format("Properties '%s' and '%s' are mutually exclusive",
|
|
IRoleManager.Option.PASSWORD, IRoleManager.Option.GENERATED_PASSWORD));
|
|
if (options.containsKey(IRoleManager.Option.HASHED_PASSWORD))
|
|
throw new InvalidRequestException(String.format("Properties '%s' and '%s' are mutually exclusive",
|
|
IRoleManager.Option.HASHED_PASSWORD, IRoleManager.Option.GENERATED_PASSWORD));
|
|
break;
|
|
case OPTIONS:
|
|
if (!(option.getValue() instanceof Map))
|
|
throw new InvalidRequestException(String.format("Invalid value for property '%s'. " +
|
|
"It must be a map",
|
|
option.getKey()));
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public String toString()
|
|
{
|
|
return FBUtilities.toString(options);
|
|
}
|
|
}
|