summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/imagemaster/server/ApiServer.java
blob: e265045ced93c18d06c1c50839c3a9934a4ed0ef (plain) (tree)
1
2
3
4
5
6
7
8
9

                                       
                           


                                                  
                           
                      
 

                                            
                                          
                                                     
                                              
                                         
                                                               



                                                                  





                                                                    
                                                               
                                                                   
                                                         
                                                      

                                                               
                                                                  
                                                             
                                                              
                                                        
                                                       
                                                            
                                                     
                                         











                                                                                

                      
 

                                                                              

                                     
           

                                                                            
                                                                                
                                                                  
           



                                                                               

                                                                                
                                                                        
                 
                                                                                
 

                                                            



                                                         
           
                                      
                                                         
                                                                           
           


                                                               
                                                                                    
                                      
                                                          

                                                                                                         
         
 
                                                                                                                         
                                                                                          
         
                                                
                                                                                   
                                                                                                                             
                 
                                                                 
                                                                                  
         
 
                                                                                                                                    
         

                                                                                   



                                                                                                                             
                                                                                                                          
                 
 
                                                                 
                                                               
         
 
           
                                                                        
           
                                                                          
                                                                              
                                                         
                                                                                     
           
                                                                                   
                                                      
         
                                                                         
                                                                                                                            
 
                                                                                         
                                        
                                                                                                                                                        
                                                    
                                                                                                                                                    
                                                                                       

         
           
                                                                              
           

                                                                          
                                                                     
                                          
           
                                                                                  
                                                                                     
         
                                                                            
                                                                                                                                                 
                 
                                                                                         
                                        
                                                                                                                              
                                                    
                                                                                                                                                    

                                                                                                                     


                                                                              
         




                                                                                      
 
                                                                                                                
         
                                 
                                                                                          

                                                                                                                         
                                                               




                                                                                 

         
                                                                                                                                         
         






                                                                                                                         



                                                               


                                                            
                                                                                                                 
         

                                                                                                                         
                                                                                 
         























                                                                                                                                               







                                                                                                                             
 
package org.openslx.imagemaster.server;

import java.nio.ByteBuffer;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.openslx.encryption.AsymKeyHolder;
import org.openslx.imagemaster.db.DbImage;
import org.openslx.imagemaster.db.DbPendingSatellite;
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;
import org.openslx.imagemaster.util.Util;

/**
 * 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
{

	private static final Logger LOG = Logger.getLogger( ApiServer.class );

	/**
	 * 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 ) throws AuthorizationException
	{
		// Check session.
		if ( SessionManager.getSessionFromSessionId( serverSessionId ) == null ) {
			throw new AuthorizationException( AuthorizationError.NOT_AUTHENTICATED, "Session ID not valid" );
		}
		if ( DbUser.forLogin( user.userId ) == null ) {
			// User not known by server. Insert into server database.
			return DbUser.insertOrUpdate( user );
		}
		// Else user is already known by server. Do nothing.
		return true;
	}

	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 );
	}

	public static boolean registerSatellite( String organizationId, String address, String modulus, String exponent )
	{
		if ( organizationId == null || address == null || exponent == null || modulus == null )
			return false;
		Key newKey;
		try {
			newKey = new AsymKeyHolder( null, Util.tryToParseBigInt( exponent ), Util.tryToParseBigInt( modulus ) ).getPublicKey();
		} catch ( NoSuchAlgorithmException | InvalidKeySpecException e ) {
			LOG.warn( "Invalid public key in registerOrganization for " + organizationId + " (" + address + ")", e );
			return false;
		}
		if ( newKey == null ) {
			LOG.warn( "Uninstantiable public key in registerOrganization for " + organizationId + " (" + address + ")" );
			return false;
		}
		DbSatellite existing = DbSatellite.fromSuffix( organizationId );
		if ( existing != null ) {
			Key existingKey = existing.getPubkey();
			if ( existingKey != null && Util.keysEqual( newKey, existingKey ) )
				return true;
		}
		return DbPendingSatellite.add( organizationId, address, modulus, exponent );
	}

	public static boolean updateSatelliteAddress( String serverSessionId, String address ) throws AuthorizationException
	{
		if ( ServerSessionManager.getSession( serverSessionId ) == null )
			throw new AuthorizationException( AuthorizationError.NOT_AUTHENTICATED, "No valid serverSessionId" );
		// TODO: Implement
		return false;
	}
}