/*
* 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.brooklyn.rest.security.provider;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.StringTokenizer;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.config.StringConfigMap;
import org.apache.brooklyn.core.internal.BrooklynProperties;
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
import org.apache.brooklyn.rest.BrooklynWebConfig;
import org.apache.brooklyn.rest.security.PasswordHasher;
/**
* Security provider which validates users against passwords according to property keys,
* as set in {@link BrooklynWebConfig#USERS} and {@link BrooklynWebConfig#PASSWORD_FOR_USER(String)}
*/
public class ExplicitUsersSecurityProvider extends AbstractSecurityProvider implements SecurityProvider {
public static final Logger LOG = LoggerFactory.getLogger(ExplicitUsersSecurityProvider.class);
protected final ManagementContext mgmt;
private boolean allowAnyUserWithValidPass;
private Set<String> allowedUsers = null;
public ExplicitUsersSecurityProvider(ManagementContext mgmt) {
this.mgmt = mgmt;
initialize();
}
private synchronized void initialize() {
if (allowedUsers != null) return;
StringConfigMap properties = mgmt.getConfig();
allowedUsers = new LinkedHashSet<String>();
String users = properties.getConfig(BrooklynWebConfig.USERS);
if (users == null) {
LOG.warn("REST has no users configured; no one will be able to log in!");
} else if ("*".equals(users)) {
LOG.info("REST allowing any user (so long as valid password is set)");
allowAnyUserWithValidPass = true;
} else {
StringTokenizer t = new StringTokenizer(users, ",");
while (t.hasMoreElements()) {
allowedUsers.add(("" + t.nextElement()).trim());
}
LOG.info("REST allowing users: " + allowedUsers);
}
}
@Override
public boolean authenticate(HttpSession session, String user, String password) {
if (session==null || user==null) return false;
if (!allowAnyUserWithValidPass) {
if (!allowedUsers.contains(user)) {
LOG.debug("REST rejecting unknown user "+user);
return false;
}
}
if (checkExplicitUserPassword(mgmt, user, password)) {
return allow(session, user);
}
return false;
}
/** checks the supplied candidate user and password against the
* expect password (or SHA-256 + SALT thereof) defined as brooklyn properties.
*/
public static boolean checkExplicitUserPassword(ManagementContext mgmt, String user, String password) {
BrooklynProperties properties = ((ManagementContextInternal)mgmt).getBrooklynProperties();
String expectedPassword = properties.getConfig(BrooklynWebConfig.PASSWORD_FOR_USER(user));
String salt = properties.getConfig(BrooklynWebConfig.SALT_FOR_USER(user));
String expectedSha256 = properties.getConfig(BrooklynWebConfig.SHA256_FOR_USER(user));
return checkPassword(password, expectedPassword, expectedSha256, salt);
}
/**
* checks a candidate password against the expected credential defined for a given user.
* the expected credentials can be supplied as an expectedPassword OR as
* a combination of the SHA-256 hash of the expected password plus a defined salt.
* the combination of the SHA+SALT allows credentials to be supplied in a non-plaintext manner.
*/
public static boolean checkPassword(String candidatePassword, String expectedPassword, String expectedPasswordSha256, String salt) {
if (expectedPassword != null) {
return expectedPassword.equals(candidatePassword);
} else if (expectedPasswordSha256 != null) {
String hashedCandidatePassword = PasswordHasher.sha256(salt, candidatePassword);
return expectedPasswordSha256.equals(hashedCandidatePassword);
}
return false;
}
}