/**
*
* 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.openejb.client;
import javax.security.auth.login.FailedLoginException;
import java.net.URI;
import java.net.URISyntaxException;
import java.rmi.RemoteException;
public class ClientSecurity {
public static final String IDENTITY_RESOLVER_STRATEGY = "openejb.client.identityResolver";
private static ServerMetaData server;
private static IdentityResolver identityResolver;
private static Object staticClientIdentity;
private static final InheritableThreadLocal<Object> threadClientIdentity = new InheritableThreadLocal<Object>();
static {
// determine the server uri
final String serverUri = System.getProperty("openejb.server.uri");
if (serverUri != null) {
// determine the server location
try {
final URI location = new URI(serverUri);
server = new ServerMetaData(location);
} catch (Exception e) {
if (!serverUri.contains("://")) {
try {
final URI location = new URI("oejb://" + serverUri);
server = new ServerMetaData(location);
} catch (URISyntaxException ignored) {
}
}
}
}
}
public static ServerMetaData getServer() {
return server;
}
public static void setServer(final ServerMetaData server) {
ClientSecurity.server = server;
}
/**
* Login the spedified user using the specified password. This is a global login for the
* entire Java Virtural Machine. If you would like to have a thread scoped login, use
* ClientSecurity.login(username, password, true);
* </p>
* This is the equivalent of ClientSecurity.login(username, password, false);
*
* @param username the user to login
* @param password the password for the user
* @throws FailedLoginException if the username and password combination are not valid or
* if there is a problem communiating with the server
*/
public static void login(final String username, final String password) throws FailedLoginException {
login(username, password, false);
}
/**
* Login the spedified user using the specified password either globally for the
* entire Java Virtural Machine or scoped to the thread.
* </p>
* When using thread scoped login, you should logout in a finally block. This particularly
* when using thread pools. If a thread is returned to the pool with a login attached to the
* thread the next user of that thread will inherit the thread scoped login.
*
* @param username the user to login
* @param password the password for the user
* @param threadScoped if true the login is scoped to the thread; otherwise the login is global
* for the entire Java Virtural Machine
* @throws FailedLoginException if the username and password combination are not valid or
* if there is a problem communiating with the server
*/
public static void login(final String username, final String password, final boolean threadScoped) throws FailedLoginException {
final Object clientIdentity = directAuthentication(username, password, server);
if (threadScoped) {
threadClientIdentity.set(clientIdentity);
} else {
staticClientIdentity = clientIdentity;
}
identityResolver = new SimpleIdentityResolver();
}
/**
* Clears the thread and global login data.
*/
public static void logout() {
threadClientIdentity.set(null);
staticClientIdentity = null;
}
/**
* This is a helper method for login modules. Directly authenticates with the server using the specified
* username and password returning the identity token for the client. This methods does not store the
* identity token and the caller must arrange for the to be available to the OpenEJB proxies via an
* IdentityResolver.
*
* @param username the username for authentication
* @param password the password for authentication
* @param server ServerMetaData
* @return the client identity token
* @throws FailedLoginException if the username password combination is not valid
*/
public static Object directAuthentication(final String username, final String password, final ServerMetaData server) throws FailedLoginException {
return directAuthentication(null, username, password, server);
}
public static Object directAuthentication(final String securityRealm, final String username, final String password, final ServerMetaData server) throws FailedLoginException {
// authenticate
final AuthenticationRequest authReq = new AuthenticationRequest(securityRealm, username, password);
final AuthenticationResponse authRes;
try {
authRes = (AuthenticationResponse) Client.request(authReq, new AuthenticationResponse(), server);
} catch (RemoteException e) {
throw (FailedLoginException) new FailedLoginException("Unable to authenticate with server " + server).initCause(e);
}
// check the response
if (authRes.getResponseCode() != ResponseCodes.AUTH_GRANTED) {
throw (FailedLoginException) new FailedLoginException("This principal is not authenticated.").initCause(authRes.getDeniedCause());
}
// return the response object
return authRes.getIdentity().getClientIdentity();
}
public static Object getIdentity() {
return getIdentityResolver().getIdentity();
}
public static IdentityResolver getIdentityResolver() {
if (identityResolver == null) {
final String strategy = System.getProperty(IDENTITY_RESOLVER_STRATEGY);
if (strategy == null) {
identityResolver = new JaasIdentityResolver();
} else {
// find the strategy class
final ResourceFinder finder = new ResourceFinder("META-INF/");
final Class identityResolverClass;
try {
identityResolverClass = finder.findClass(IdentityResolver.class.getName() + "/" + strategy);
} catch (Exception e) {
throw new IllegalArgumentException("Could not find client identity strategy '" + strategy + "'");
}
// verify the interface
if (!IdentityResolver.class.isAssignableFrom(identityResolverClass)) {
throw new IllegalArgumentException("Client identity strategy '" + strategy + "' " +
"class '" + identityResolverClass.getName() + "' does not implement the " +
"interface '" + IdentityResolver.class.getSimpleName() + "'");
}
// create the class
try {
identityResolver = (IdentityResolver) identityResolverClass.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("Unable to create client identity strategy '" + strategy + "' " +
"class '" + identityResolverClass.getName() + "'", e);
}
}
}
return identityResolver;
}
public static void setIdentityResolver(final IdentityResolver identityResolver) {
ClientSecurity.identityResolver = identityResolver;
}
private ClientSecurity() {
}
public static class SimpleIdentityResolver implements IdentityResolver {
@Override
public Object getIdentity() {
Object clientIdentity = threadClientIdentity.get();
if (clientIdentity == null) {
clientIdentity = staticClientIdentity;
}
return clientIdentity;
}
}
}