package org.openslx.imagemaster.server;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.openslx.imagemaster.db.DbImage;
import org.openslx.imagemaster.db.DbSatellite;
import org.openslx.imagemaster.db.DbUser;
import org.openslx.imagemaster.serverconnection.ImageProcessor;
import org.openslx.imagemaster.serversession.ServerAuthenticator;
import org.openslx.imagemaster.serversession.ServerSession;
import org.openslx.imagemaster.serversession.ServerSessionManager;
import org.openslx.imagemaster.serversession.ServerUser;
import org.openslx.imagemaster.session.Authenticator;
import org.openslx.imagemaster.session.Session;
import org.openslx.imagemaster.session.SessionManager;
import org.openslx.imagemaster.session.User;
import org.openslx.imagemaster.thrift.iface.AuthenticationError;
import org.openslx.imagemaster.thrift.iface.AuthenticationException;
import org.openslx.imagemaster.thrift.iface.AuthorizationError;
import org.openslx.imagemaster.thrift.iface.AuthorizationException;
import org.openslx.imagemaster.thrift.iface.DownloadData;
import org.openslx.imagemaster.thrift.iface.ImageData;
import org.openslx.imagemaster.thrift.iface.ImageDataError;
import org.openslx.imagemaster.thrift.iface.ImageDataException;
import org.openslx.imagemaster.thrift.iface.InvalidTokenException;
import org.openslx.imagemaster.thrift.iface.OrganizationData;
import org.openslx.imagemaster.thrift.iface.ServerSessionData;
import org.openslx.imagemaster.thrift.iface.SessionData;
import org.openslx.imagemaster.thrift.iface.UploadData;
import org.openslx.imagemaster.thrift.iface.UploadException;
import org.openslx.imagemaster.thrift.iface.UserInfo;
/**
* API Server This is where all the requests from the outside arrive. We don't
* handle them directly in the Thrift handlers, as we might be adding other APIs
* later, like JSON/SOAP/REST/HTTP/XML or some other stuff. They'd all just
* interface with this static class here. Note that we use the exceptions from
* the thrift interface that you can simply catch in any other API handler and
* eg. transform into error codes, if the API doesn't support exceptions.
*
* This will be accessed from multiple threads, so use synchronization when
* needed (or in doubt)
*/
public class ApiServer
{
/**
* Request for authentication
*
* @param login The user's login in the form "user@organization.com"
* @param password user's password
* @return SessionData struct with session id/token iff login successful
* @throws AuthenticationException if login not successful
*/
public static SessionData authenticate( String login, String password )
throws AuthenticationException
{
if ( login == null || password == null ) {
throw new AuthenticationException(
AuthenticationError.INVALID_CREDENTIALS,
"Empty username or password!" );
}
final User user = Authenticator.authenticate( login, password );
final Session session = new Session( user );
return SessionManager.addSession( session );
}
/**
* Request information about user for given token
*
* @param token a user's token
* @return UserInfo struct for given token's user
* @throws InvalidTokenException if no user matches the given token
*/
public static UserInfo getUserFromToken( String token )
throws InvalidTokenException
{
final Session session = SessionManager.getSessionFromToken( token );
if ( session == null )
throw new InvalidTokenException();
return new UserInfo( session.getLogin(), session.getFirstName(),
session.getLastName(), session.getEMail(), session.getOrgenizationId() );
}
public static UploadData submitImage( String serverSessionId, ImageData imageDescription, List<Integer> crcSums )
throws AuthorizationException, ImageDataException, UploadException
{
// first check session of server
if ( ServerSessionManager.getSession( serverSessionId ) == null ) {
throw new AuthorizationException( AuthorizationError.NOT_AUTHENTICATED, "No valid serverSessionId" );
}
// then let the image processor decide what to do
return ImageProcessor.getUploadInfos( imageDescription, crcSums );
}
public static DownloadData getImage( String uuid, String serverSessionId ) throws AuthorizationException, ImageDataException
{
// first check session of server
if ( ServerSessionManager.getSession( serverSessionId ) == null ) {
throw new AuthorizationException( AuthorizationError.NOT_AUTHENTICATED, "No valid serverSessionId" );
}
if ( !DbImage.exists( uuid ) ) {
throw new ImageDataException( ImageDataError.UNKNOWN_IMAGE, "UUID is not known by this server." );
}
// then let the image processor decide what to do
return ImageProcessor.getDownloadInfos( uuid );
}
/**
* Start the server authentication of a uni/hs satellite server.
*
* @param organization the organization that the server belongs to
* @return a random string that needs to be encrypted with the private
* key of the requesting satellite server
* @throws ServerAuthenticationException when organization is invalid/unknown
*/
public static ByteBuffer startServerAuthentication( String organizationId )
throws AuthenticationException
{
if ( organizationId == null || organizationId.isEmpty() )
throw new AuthenticationException( AuthenticationError.INVALID_ORGANIZATION, "Empty organization" );
DbSatellite satellite = DbSatellite.fromOrganizationId( organizationId );
if ( satellite == null )
throw new AuthenticationException( AuthenticationError.INVALID_ORGANIZATION, "Unknown organization: '" + organizationId + "'" );
if ( satellite.getPubkey() == null )
throw new AuthenticationException( AuthenticationError.INVALID_KEY, "There is no public key known for your organization." );
return ServerAuthenticator.startServerAuthentication( organizationId );
}
/**
* Authenticate the uni/hs satellite server with the encrypted string.
*
* @param organization the organization that the server belongs to
* @param challengeResponse the encrypted string
* @return session data iff the authentication was successful
* @throws AuthenticationException
*/
public static ServerSessionData serverAuthenticate( String organizationId,
ByteBuffer challengeResponse ) throws AuthenticationException
{
if ( organizationId == null || challengeResponse == null ) {
throw new AuthenticationException( AuthenticationError.INVALID_ORGANIZATION, "Empty organization or challengeResponse" );
}
DbSatellite satellite = DbSatellite.fromOrganizationId( organizationId );
if ( satellite == null )
throw new AuthenticationException( AuthenticationError.INVALID_ORGANIZATION, "Unknown organization" );
if ( satellite.getPubkey() == null )
throw new AuthenticationException( AuthenticationError.INVALID_KEY, "There is no public key known for your organization." );
final ServerUser serverUser = ServerAuthenticator.serverAuthenticate( satellite, challengeResponse );
final ServerSession session = new ServerSession( serverUser );
return ServerSessionManager.addSession( session );
}
public static boolean isServerAuthenticated( String serverSessionId )
{
return ( ServerSessionManager.getSession( serverSessionId ) != null );
}
public static boolean publishUser( String serverSessionId, UserInfo user )
{
// TODO
return false;
}
public static List<UserInfo> findUser( String sessionId, String organizationId, String searchTerm ) throws AuthorizationException
{
// Needs to be a logged in user
if ( SessionManager.getSessionFromSessionId( sessionId ) == null )
throw new AuthorizationException( AuthorizationError.NOT_AUTHENTICATED, "Session ID not valid" );
// Search string needs to be at least 2 characters (FIXME: quick and dirty ignoring LIKE chars)
if ( searchTerm == null || searchTerm.length() < 2 || searchTerm.replaceAll( "[%_]", "" ).length() < 2 )
return new ArrayList<>( 0 );
return DbUser.findUser( organizationId, searchTerm );
}
public static List<OrganizationData> getOrganizations()
{
return DbSatellite.asOrganizationDataList();
}
public static List<ImageData> getPublicImages( String sessionId, int page ) throws AuthorizationException
{
if ( SessionManager.getSessionFromSessionId( sessionId ) == null )
throw new AuthorizationException( AuthorizationError.NOT_AUTHENTICATED, "Session ID not valid" );
return DbImage.asImageDataList( page * 100, ( page + 1 ) * 100 );
}
}