/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed 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.uberfire.backend.server.security;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import org.jboss.errai.security.shared.api.identity.User;
import org.jboss.errai.security.shared.exception.AuthenticationException;
import org.jboss.errai.security.shared.service.AuthenticationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.uberfire.commons.services.cdi.Startup;
import org.uberfire.java.nio.file.api.FileSystemProviders;
import org.uberfire.java.nio.file.spi.FileSystemProvider;
import org.uberfire.java.nio.security.FileSystemUser;
import org.uberfire.java.nio.security.SecuredFileSystemProvider;
import org.uberfire.security.authz.AuthorizationManager;
@ApplicationScoped
@Startup
public class IOServiceSecuritySetup {
/**
* The system property that specifies which authentication domain the default security service should be configured
* for. Not used if the application provides its own {@code @IOSecurityAuth AuthenticationService}.
*/
public static final String AUTH_DOMAIN_KEY = "org.uberfire.domain";
private static final Logger LOG = LoggerFactory.getLogger(IOServiceSecuritySetup.class);
@Inject
@IOSecurityAuth
Instance<AuthenticationService> authenticationManagers;
@Inject
AuthorizationManager authorizationManager;
@PostConstruct
public void setup() {
final AuthenticationService authenticationManager;
if (authenticationManagers.isUnsatisfied()) {
final String authType = System.getProperty("org.uberfire.io.auth",
null);
final String domain = System.getProperty(AUTH_DOMAIN_KEY,
JAASAuthenticationService.DEFAULT_DOMAIN);
if (authType == null || authType.toLowerCase().equals("jaas") || authType.toLowerCase().equals("container")) {
authenticationManager = new JAASAuthenticationService(domain);
} else {
authenticationManager = loadClazz(authType,
AuthenticationService.class);
}
} else {
authenticationManager = authenticationManagers.get();
}
for (final FileSystemProvider fp : FileSystemProviders.installedProviders()) {
if (fp instanceof SecuredFileSystemProvider) {
SecuredFileSystemProvider sfp = (SecuredFileSystemProvider) fp;
sfp.setAuthenticator((username, password) -> {
try {
final User result = authenticationManager.login(username,
password);
if (result != null) {
return new UserAdapter(result);
}
return null;
} catch (final AuthenticationException loginFailed) {
LOG.warn("Login failed",
loginFailed);
return null;
}
}
);
sfp.setAuthorizer((fs, fileSystemUser) ->
authorizationManager.authorize(
new FileSystemResourceAdaptor(fs),
((UserAdapter) fileSystemUser).getWrappedUser())
);
}
}
}
private <T> T loadClazz(final String clazzName,
final Class<T> typeOf) {
if (clazzName == null || clazzName.isEmpty()) {
return null;
}
try {
final Class<?> clazz = Class.forName(clazzName);
if (!typeOf.isAssignableFrom(clazz)) {
// FIXME this could only be due to a deployment configuration error. why do we continue in this case?
LOG.error("Class '" + clazzName + "' is not assignable to expected type " + typeOf + ". Continuing as if no class was specified.");
return null;
}
return typeOf.cast(clazz.newInstance());
} catch (final Exception e) {
// FIXME this could only be due to a deployment error. why do we continue in this case?
LOG.error("Failed to load class '" + clazzName + "' as type " + typeOf + ". Continuing as if none was specified.",
e);
}
return null;
}
static class UserAdapter implements FileSystemUser {
private final User user;
UserAdapter(User user) {
this.user = user;
}
@Override
public String getName() {
return user.getIdentifier();
}
public User getWrappedUser() {
return user;
}
}
}