All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.synedge.oss.client.authentication.AuthenticatedClient.groovy Maven / Gradle / Ivy

Go to download

This client allows you to easily connect to the Synedge API with any language running on the JDK

The newest version!
package com.synedge.oss.client.authentication

import com.synedge.oss.client.ClientVersion
import com.synedge.oss.client.exceptions.SynedgeClientAuthenticationException
import com.synedge.oss.client.exceptions.SynedgeClientException
import groovy.json.JsonSlurper
import groovy.transform.CompileStatic
import groovy.transform.TypeCheckingMode
import groovy.util.logging.Slf4j
import org.glassfish.jersey.client.JerseyClient
import org.glassfish.jersey.client.JerseyClientBuilder

import javax.ws.rs.WebApplicationException
import javax.ws.rs.client.ClientRequestContext
import javax.ws.rs.client.ClientRequestFilter
import javax.ws.rs.client.Entity
import javax.ws.rs.client.Invocation.Builder
import javax.ws.rs.core.MultivaluedHashMap
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import java.security.MessageDigest
import java.util.concurrent.ConcurrentHashMap

@Slf4j
@CompileStatic
class AuthenticatedClient {
    private static final String CLIENT_ID = "synedge-java-client-${ClientVersion.version}"
    private static final String USER_AGENT = "Synedge Java Client (${ClientVersion.version})"
    private static final Map AUTHENTICATION_MAP = new ConcurrentHashMap<>()
    private final Random random = new Random()
    private final String authenticationKey
    protected final JsonSlurper jsonSlurper = new JsonSlurper()
    protected final JerseyClient client
    protected final String endpoint

    protected AuthenticatedClient(String username, String password, String endpoint) {
        this.client = JerseyClientBuilder.createClient().register(UserAgent)
        this.endpoint = endpoint
        this.authenticationKey = MessageDigest.getInstance("MD5").digest((username + '-' + password + '-' + endpoint).bytes).encodeHex().toString()
        if (AUTHENTICATION_MAP.containsKey(authenticationKey)) {
            return;
        }
        String clientSecret = generateRandomString(12)
        AuthInfo authInfo = login(username, password, clientSecret)
        AUTHENTICATION_MAP.put(authenticationKey, authInfo)
    }

    private final AuthInfo login(String username, String password, String clientSecret) {
        MultivaluedMap formData = new MultivaluedHashMap<>();
        formData.add('username', username)
        formData.add('password', password)
        formData.add('client_id', CLIENT_ID)
        formData.add('client_secret', clientSecret)
        formData.add('grant_type', 'password')
        try {
            return handleAuthResult(client.target(endpoint).path('auth').path('token').request().post(Entity.form(formData), String.class), clientSecret)
        }
        catch (WebApplicationException e) {
            String response = e.response.readEntity(String)
            // Check auth errors
            log.error('Error logging in: ' + response, e)
            throw new SynedgeClientAuthenticationException(response)
        }
    }
    
    @CompileStatic(TypeCheckingMode.SKIP)
    private final AuthInfo handleAuthResult(String result, String clientSecret) {
        def authResult = jsonSlurper.parseText(result)
        new AuthInfo(System.currentTimeMillis() + (authResult.expires_in as int) - 60, authResult.access_token as String, authResult.refresh_token as String, clientSecret)
    }

    private final void refresh() {
        AuthInfo authInfo = AUTHENTICATION_MAP.get(authenticationKey)
        MultivaluedMap formData = new MultivaluedHashMap<>();
        formData.add('client_id', CLIENT_ID)
        formData.add('client_secret', authInfo.clientSecret)
        formData.add('grant_type', 'refresh_token')
        formData.add('refresh_token', authInfo.refreshToken)
        try {
            AUTHENTICATION_MAP.put(authenticationKey, handleAuthResult(client.target(endpoint).path('auth').path('token').request().post(Entity.form(formData), String.class), authInfo.clientSecret))
        }
        catch (WebApplicationException e) {
            String response = e.response.readEntity(String)
            // Check auth errors
            log.error('Error logging in: ' + response, e)
            throw new SynedgeClientAuthenticationException(response)
        }
    }

    protected Builder sign(Builder webTarget) {
        AuthInfo authInfo = AUTHENTICATION_MAP.get(authenticationKey)
        if (authInfo.tokenExpires < System.currentTimeMillis()) {
            refresh()
        }
        webTarget.header("Authorization", "Bearer " + authInfo.accessToken)
    }

    private final String generateRandomString(int length) {
        new BigInteger(length * 8, random).toString(16).substring(0, length)
    }
    
    protected final Object signAndGet(Builder webTarget) {
        throwErrorOrReturnJson(sign(webTarget).get())
    }
    
    protected final Object signAndPost(Builder webTarget, Entity entity) {
        throwErrorOrReturnJson(sign(webTarget).post(entity));
    }
    
    @CompileStatic(TypeCheckingMode.SKIP)
    protected final Object throwErrorOrReturnJson(Response response) {
        String responseStr = response.readEntity(String)
        if (responseStr == null) {
            throw new SynedgeClientAuthenticationException(response.getHeaderString('WWW-Authenticate'))
        }
        def result = jsonSlurper.parseText(responseStr)
        if (result.error) {
            throw new SynedgeClientException(result.message)
        }
        result.response
    }
    
    private static class UserAgent implements ClientRequestFilter {
        @Override
        public void filter(ClientRequestContext requestContext) throws IOException {
            requestContext.getHeaders().remove('User-Agent')
            requestContext.getHeaders().add('User-Agent', USER_AGENT)
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy