android-ngn-stack/src/main/java/org/doubango/ngn/services/impl/ms/AuthenticacionUtils.java
175b478c
 /*
 
74ca6d11
 *  Copyright (C) 2020, University of the Basque Country (UPV/EHU)
175b478c
 *
 * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
 *
 * This file is part of MCOP MCPTT Client
 *
 * This is free software: you can redistribute it and/or modify it under the terms of
 * the GNU General Public License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * This is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 
 package org.doubango.ngn.services.impl.ms;
 
 
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.net.Uri;
 import android.support.annotation.NonNull;
 import android.util.Log;
 
 import net.openid.appauth.AppAuthConfiguration;
 import net.openid.appauth.AuthState;
 import net.openid.appauth.AuthorizationRequest;
 import net.openid.appauth.AuthorizationServiceConfiguration;
 import net.openid.appauth.ResponseTypeValues;
 import net.openid.appauth.browser.BrowserWhitelist;
 import net.openid.appauth.browser.VersionedBrowserMatcher;
 import net.openid.appauth.connectivity.ConnectionBuilder;
 
 import org.doubango.ngn.datatype.mcpttinfo.ContentType;
 import org.doubango.ngn.datatype.mcpttinfo.McpttParamsType;
 import org.doubango.ngn.datatype.mcpttinfo.McpttinfoType;
 import org.doubango.ngn.datatype.mcpttinfo.ProtectionType;
 import org.doubango.ngn.datatype.openId.CampsType;
 import org.doubango.ngn.datatype.pocsettings.AmSettingType;
 import org.doubango.ngn.datatype.pocsettings.EntityType;
 import org.doubango.ngn.datatype.pocsettings.PocSettingsType;
 import org.doubango.ngn.datatype.pocsettings.SelectedUserProfileIndex;
 import org.doubango.utils.Utils;
 import org.jose4j.base64url.internal.apache.commons.codec.binary.Base64;
 import org.jose4j.json.internal.json_simple.JSONArray;
 import org.jose4j.json.internal.json_simple.JSONObject;
 import org.jose4j.json.internal.json_simple.JSONValue;
 import org.jose4j.jwk.JsonWebKey;
 import org.jose4j.lang.JoseException;
 import org.json.JSONException;
 import org.simpleframework.xml.Serializer;
 import org.simpleframework.xml.convert.AnnotationStrategy;
 import org.simpleframework.xml.core.Persister;
 import org.simpleframework.xml.strategy.Strategy;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 
 
 public class AuthenticacionUtils {
     private final static String TAG = Utils.getTAG(AuthenticacionUtils.class.getCanonicalName());
     private final static String AUTHENTICATION_PREFERENCE="AUTHENTICATION_PREFERENCE";
     private final static String AUTHENTICATION_PREFERENCE_AUTH_STATE="AUTHENTICATION_PREFERENCE_AUTH_STATE";
     private final static String AUTHENTICATION_PREFERENCE_AUTH_CAMPS="AUTHENTICATION_PREFERENCE_AUTH_CAMPS";
     private final static String SCOPES_DEFUALT_OLD="openid 3gpp:mcptt:ptt_server 3gpp:mcptt:key_management_server 3gpp:mcptt:config_management_server 3gpp:mcptt:group_management_server";
     private final static String SCOPES_DEFUALT="3gpp:mc:data_group_management_service 3gpp:mc:video_service 3gpp:mc:data_config_management_service openid 3gpp:mc:ptt_service 3gpp:mc:video_key_management_service 3gpp:mc:data_service 3gpp:mc:video_config_management_service 3gpp:mc:ptt_group_management_service 3gpp:mc:video_group_management_service 3gpp:mc:ptt_key_management_service 3gpp:mc:data_key_management_service 3gpp:mc:ptt_config_management_service";
     private static AuthState authStateNow;
     private static CampsType campsTypesNow;
 
 
 
     //INIT SAVE DATA AUTHENTICATION
     @NonNull
     public static AuthState readAuthState(Context context) throws JSONException {
         if(authStateNow==null){
             SharedPreferences authPrefs = context.getSharedPreferences(AUTHENTICATION_PREFERENCE,context.MODE_PRIVATE);
             String stateJson = authPrefs.getString(AUTHENTICATION_PREFERENCE_AUTH_STATE,null);
             if (stateJson != null){
                 return AuthState.jsonDeserialize(stateJson);
             }
             else {
                 return new AuthState();
             }
         }
         return authStateNow;
 
     }
 
     public static void writeAuthState( AuthState state,@NonNull Context context) {
 
         if(context!=null){
             String dataWrite=null;
             if(state!=null){
                 authStateNow=state;
                 dataWrite=authStateNow.jsonSerializeString();
             }else{
                 authStateNow=state;
             }
             SharedPreferences authPrefs = context.getSharedPreferences(AUTHENTICATION_PREFERENCE, context.MODE_PRIVATE);
             authPrefs.edit()
                     .putString(AUTHENTICATION_PREFERENCE_AUTH_STATE,dataWrite )
                     .apply();
         }
 
 
     }
 
 
     protected static CampsType readAuthCamps(Context context) throws JSONException {
         if(campsTypesNow!=null){
             return campsTypesNow;
         }
         SharedPreferences authPrefs = context.getSharedPreferences(AUTHENTICATION_PREFERENCE,context.MODE_PRIVATE);
         String campsString = authPrefs.getString(AUTHENTICATION_PREFERENCE_AUTH_CAMPS,null);
         if (campsString != null){
             try {
                 return CampsType.jsonDeserialize(campsString);
             } catch (IOException e) {
                 return new CampsType();
             }
         }
         else {
             return new CampsType();
         }
     }
 
     protected static boolean writeAuthCamps(@NonNull CampsType campsType, Context context) {
         if(context!=null){
             campsTypesNow=campsType;
             SharedPreferences authPrefs = context.getSharedPreferences(AUTHENTICATION_PREFERENCE, context.MODE_PRIVATE);
             SharedPreferences.Editor editor = authPrefs.edit();
             try {
 
 
                 if(campsType==null){
                     editor.remove(AUTHENTICATION_PREFERENCE_AUTH_CAMPS);
                     editor.apply();
                     return true;
                 }else {
                     String data=null;
                     data=campsType.jsonSerializeString();
                     editor.putString(AUTHENTICATION_PREFERENCE_AUTH_CAMPS, data).apply();
                     return editor.commit();
                 }
             } catch (IOException e) {
                 Log.e(TAG,"Error in write Camps datas:"+e.getMessage());
                 return false;
             } catch (JSONException e) {
                 Log.e(TAG,"Error in write Camps datas 2");
                 return false;
             }
 
         }
         return false;
     }
 
 
     //END SAVE DATA AUTHENTICATION
     public static JsonWebKey getProviderRSAJWK(String is, String keyID) throws java.text.ParseException {
         // Read all data from stream
 
         //StringBuilder sb = new StringBuilder();
         //try (Scanner scanner = new Scanner(is);) {
         //    while (scanner.hasNext()) {
         //        sb.append(scanner.next());
         //    }
         //}
 
 
         // Parse data as json
         //String jsonString = sb.toString();
         JSONObject json = null;
         json = (JSONObject) JSONValue.parse(is);
 
         // Find the RSA signing key
         JSONArray keyList = null;
         if(json==null){
             Log.e(TAG,"Error processing JSONObject");
             return null;
         }
 
         keyList = (JSONArray) json.get("keys");
 
         for (Object key : keyList) {
             JSONObject k = (JSONObject) key;
 
             if (k.get("kid").equals(keyID) && k.get("kty").equals("RSA")) {
                 try {
                     JsonWebKey jwk = JsonWebKey.Factory.newJwk(k);
                     return jwk;
                 } catch (JoseException e) {
                     e.printStackTrace();
                 }
 
             }
 
         }
 
 
         return null;
     }
 
 
      //Generates network configuration in authentication
      //@return network configuration
 
     public static AppAuthConfiguration generateConfigureNet(){
         AppAuthConfiguration appAuthConfig = new AppAuthConfiguration.Builder()
                 .setBrowserMatcher(new BrowserWhitelist(
                         VersionedBrowserMatcher.CHROME_CUSTOM_TAB,
                         VersionedBrowserMatcher.FIREFOX_BROWSER,
                         VersionedBrowserMatcher.SAMSUNG_BROWSER,
                         VersionedBrowserMatcher.SAMSUNG_CUSTOM_TAB))
                 .setConnectionBuilder(new ConnectionBuilder() {
                     @NonNull
                     @Override
                     public HttpURLConnection openConnection(@NonNull Uri uri) throws IOException {
                         URL url = new URL(uri.toString());
                         HttpURLConnection connection =(HttpURLConnection) url.openConnection();
 
 
                         //if (connection instanceof HttpsURLConnection) {
                         //    HttpsURLConnection connection = (HttpsURLConnection) connection;
                         //    connection.setSSLSocketFactory(MySocketFactory.getInstance());
                         //}
                         return connection;
                     }
                 })
                 .build();
 
         return appAuthConfig;
     }
     //INIT utils xml
         //INIT MCPTT-INFO
 
     protected static McpttinfoType getMcpttinfoType(String string) throws Exception {
         return getMcpttinfoType(string.getBytes());
     }
 
     private static McpttinfoType getMcpttinfoType(byte[] bytes) throws Exception {
         return getMcpttinfoType(new ByteArrayInputStream(bytes));
     }
     private static McpttinfoType getMcpttinfoType(InputStream stream) throws Exception {
         if(stream==null)return null;
         Strategy strategy = new AnnotationStrategy();
         Serializer serializer = new Persister(strategy);
         return serializer.read(McpttinfoType.class,stream);
     }
 
 
     private static InputStream getOutputStreamOfMcpttinfoType(Context context, McpttinfoType mcpttinfoType) throws Exception {
         if(mcpttinfoType==null)return null;
         Strategy strategy = new AnnotationStrategy();
         Serializer serializer = new Persister(strategy);
         File outputDir = context.getCacheDir();
         File outputFile = File.createTempFile(String.valueOf(Calendar.getInstance().getTimeInMillis()), "txt", outputDir);
         serializer.write(mcpttinfoType,outputFile);
         return new FileInputStream(outputFile);
     }
 
     private static byte[] getBytesOfMcpttinfoType(Context context,McpttinfoType mcpttinfoType) throws Exception {
         InputStream inputStream=getOutputStreamOfMcpttinfoType(context,mcpttinfoType);
         if(inputStream==null)return null;
         return readBytes(inputStream);
     }
 
     private  static String  getStringOfMcpttinfoType(Context context,McpttinfoType mcpttinfoType) throws Exception {
         return new String(getBytesOfMcpttinfoType(context,mcpttinfoType)).trim();
     }
 
     private static McpttinfoType generateMcpttinfoType(CampsType campsTypeCurrent,String mcpttId,String mcpttClientIdString){
         McpttinfoType mcpttinfoType=new McpttinfoType();
         McpttParamsType mcpttParamsType=new McpttParamsType();
         mcpttinfoType.setMcpttParams(mcpttParamsType);
         if(mcpttClientIdString!=null &&
                 !mcpttClientIdString.trim().isEmpty()
                 ){
             ContentType mcpttClientId=new ContentType();
             mcpttClientId.setType(ProtectionType.Normal);
             mcpttParamsType.setMcpttClientId(mcpttClientId);
             mcpttClientId.setMcpttString(mcpttClientIdString.trim());
         }
 
         if(campsTypeCurrent!=null &&
                 campsTypeCurrent.getAccessToken()!=null &&
                 !campsTypeCurrent.getAccessToken().trim().isEmpty()){
             ContentType accessToken=new ContentType();
             accessToken.setType(ProtectionType.Normal);
             mcpttParamsType.setMcpttAccessToken(accessToken);
             accessToken.setMcpttString(campsTypeCurrent.getAccessToken().trim());
         }
         if(mcpttId!=null &&
                 !mcpttId.trim().isEmpty()
                 ){
             ContentType mcpttIdContentType=new ContentType();
             mcpttParamsType.setMcpttRequestUri(mcpttIdContentType);
             mcpttIdContentType.setType(ProtectionType.Normal);
             mcpttIdContentType.setMcpttURI(mcpttId);
         }
 
         return  mcpttinfoType;
 
     }
 
     protected static String generateMcpttinfoType(Context context,CampsType campsTypeCurrent,String mcpttIdString,String mcpttClientIdString){
         McpttinfoType mcpttinfoType=generateMcpttinfoType(campsTypeCurrent,mcpttIdString,mcpttClientIdString);
         if(mcpttinfoType!=null){
             try {
                 return getStringOfMcpttinfoType(context,mcpttinfoType);
             } catch (Exception e) {
                 Log.e(TAG,"Error generating Mcptt-info.");
             }
         }
         return null;
     }
 
 
 
 
     /**
      * In this function, if the campsTypeCurrentToGenerate is null, the device will generate mcpttinfo with token fail.
      * @param context
      * @param campsTypeCurrentToGenerate
      * @param mcpttClientIdString
      * @return
      */
     protected static String generateMcpttinfoType(@NonNull Context context,CampsType campsTypeCurrentToGenerate,@NonNull String mcpttId,@NonNull String mcpttClientIdString, boolean sendTokenFail){
         if((campsTypeCurrentToGenerate==null ||
                 campsTypeCurrentToGenerate.getAccessToken()==null ||
                 campsTypeCurrentToGenerate.getAccessToken().isEmpty())
                 && sendTokenFail){
             if(mcpttId!=null){
                 String data = String.format("{\"mcptt_id\":\"%s\",\"sub\":\"mcptt-client-A\",\"azp\":\"mcptt_client\",\"scope\":[\"3gpp:mcptt:ptt_server\",\"openid\",\"3gpp:mcptt:config_management_server\",\"3gpp:mcptt:key_management_server\",\"3gpp:mcptt:group_management_server\"],\"iss\":\"http:\\/\\/idms.organization.org:8080\\/openid-connect-server-webapp\\/\",\"exp\":1492767428,\"iat\":1492763828,\"jti\":\"b099481f-199b-41f9-8396-48eed364b288\",\"client_id\":\"mcptt_client\"}",
                         mcpttId);
                 byte[]   bytesEncoded = Base64.encodeBase64(data .getBytes());
                 String stringEncoded = new String(bytesEncoded);
                 if(!stringEncoded.isEmpty()){
                     CampsType campsType=new CampsType();
                     String accessTokenFail=String.format("eyJraWQiOiJyc2ExIiwiYWxnIjoiUlMyNTYifQ.%s.Q3RO7otkthtACrL9tya9-CRn9rtQBoH2XC4lZJCoTau4SPQ2gTllT2qJRSg0ciNgNgj1zq_cmnZZ1mM7E3HME_4gM0ATyHPZg5hv0gIquKvZUDs6sDZDDcmHwZTg6koZYv-XaQxtQCZwmyZ8OJXuQELaYAJ2rBaB0EnubrTmZdHKnvnWzpIjz1skI8AOnfBM8ixisBKpUaTi3TLETLmGJDY_k6YdPo5z18kZ_2SppJXPLOcxr7Z4r2VmsD3ZYSq_cnZwPcC_IhoLObfrW_N-Mki-lqRd5nw4TyURMLbuZRaRVnC7aUQBempb31OztjEm6y_UPtyxb_qQ9p8cTO_E6A",
                             stringEncoded);
                     if(accessTokenFail!=null && !accessTokenFail.isEmpty()){
                         Log.d(TAG,"Send access token Fail");
                         campsType.setAccessToken(accessTokenFail);
                         return  generateMcpttinfoType(context,campsType,mcpttId,mcpttClientIdString);
                     }
                 }
             }
 
         }
 
         return generateMcpttinfoType(context,campsTypeCurrentToGenerate,mcpttId,mcpttClientIdString);
     }
         //END MCPTT-INFO
 
         //INIT POC-SETTINGS
     private static PocSettingsType generatePocSettingsType(boolean isManual,int indexUserProfile){
         PocSettingsType pocSettingsType=new PocSettingsType();
         ArrayList<EntityType> entityTypes=new ArrayList<>();
         pocSettingsType.setEntity(entityTypes);
         EntityType entity=new EntityType();
         entityTypes.add(entity);
         AmSettingType answerMode=new AmSettingType();
         entity.setAmSettings(answerMode);
         entity.setId(randomStringUUID());
         if(isManual){
             answerMode.setAnswerMode("manual");
         }else{
             answerMode.setAnswerMode("automatic");
         }
         if(indexUserProfile>=0){
             SelectedUserProfileIndex selectedUserProfileIndex=new SelectedUserProfileIndex();
             selectedUserProfileIndex.setUserProfileIndex(indexUserProfile);
             entity.setSelectedUserProfileIndex(new SelectedUserProfileIndex());
         }
         return pocSettingsType;
     }
 
     protected static String generatePocSettingsType(@NonNull Context context,boolean isManual,int indexUserProfile){
         PocSettingsType pocSettingsType=generatePocSettingsType(isManual,indexUserProfile);
         if(pocSettingsType!=null){
             try {
                 return getStringOfPocSettingsType(context,pocSettingsType);
             } catch (Exception e) {
                 Log.e(TAG,"Invalid parameters to generate poc-settings: "+e.getMessage());
             }
         }
         return null;
     }
 
     protected static String generatePocSettingsType(@NonNull Context context,boolean isManual){
         PocSettingsType pocSettingsType=generatePocSettingsType(isManual,-1);
         if(pocSettingsType!=null){
             try {
                 return getStringOfPocSettingsType(context,pocSettingsType);
             } catch (Exception e) {
                 Log.e(TAG,"Invalid parameters to generate poc-settings: "+e.getMessage());
             }
         }
         return null;
     }
 
     protected static PocSettingsType getPocSettingsType(String string) throws Exception {
         return getPocSettingsType(string.getBytes());
     }
 
     protected static PocSettingsType getPocSettingsType(byte[] bytes) throws Exception {
         return getPocSettingsType(new ByteArrayInputStream(bytes));
     }
     protected static PocSettingsType getPocSettingsType(InputStream stream) throws Exception {
         if(stream==null)return null;
         Strategy strategy = new AnnotationStrategy();
         Serializer serializer = new Persister(strategy);
         return serializer.read(PocSettingsType.class,stream);
     }
 
 
     protected static InputStream getOutputStreamOfPocSettingsType(Context context, PocSettingsType pocSettingsType) throws Exception {
         if(pocSettingsType==null)return null;
         Strategy strategy = new AnnotationStrategy();
         Serializer serializer = new Persister(strategy);
         File outputDir = context.getCacheDir(); // context being the Activity pointer
         File outputFile = File.createTempFile(String.valueOf(Calendar.getInstance().getTimeInMillis()), "txt", outputDir);
         serializer.write(pocSettingsType,outputFile);
         InputStream inputStream = new FileInputStream(outputFile);
         return inputStream;
     }
 
     protected static byte[] getBytesOfPocSettingsType(Context context,PocSettingsType pocSettingsType) throws Exception {
         InputStream inputStream=getOutputStreamOfPocSettingsType(context,pocSettingsType);
         if(inputStream==null)return null;
         return readBytes(inputStream);
     }
 
     protected  static String  getStringOfPocSettingsType(Context context,PocSettingsType pocSettingsType) throws Exception {
         return new String(getBytesOfPocSettingsType(context,pocSettingsType)).trim();
     }
         //END POC-SETTINGS
 
     private static byte[] readBytes(InputStream inputStream) throws IOException {
 
         ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
 
 
         int bufferSize = 1024;
         byte[] buffer = new byte[bufferSize];
 
 
         int len = 0;
         while ((len = inputStream.read(buffer)) != -1) {
             byteBuffer.write(buffer, 0, len);
         }
 
 
         return byteBuffer.toByteArray();
     }
     //END utils xml
 
     private static String randomStringUUID() {
         //
         // Creating a random UUID (Universally unique identifier).
         //
         UUID uuid = UUID.randomUUID();
         String randomUUIDString = uuid.toString();
         return randomUUIDString;
     }
 
 
     protected static String getDatas(Context context,Calendar calendar){
         if(context==null)return "";
         SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
         String date=format1.format(calendar.getTime());
         return date;
     }
     protected static AuthorizationRequest getAuthorizationRequest(@NonNull AuthorizationServiceConfiguration serviceConfiguration, @NonNull AuthorizationServiceConfiguration authorizationServiceConfiguration, @NonNull String client_id, @NonNull Uri redirectUri){
         return  getAuthorizationRequest(  serviceConfiguration,   authorizationServiceConfiguration,   client_id,   redirectUri, false);
 
         }
 
 
         protected static AuthorizationRequest getAuthorizationRequest(@NonNull AuthorizationServiceConfiguration serviceConfiguration, @NonNull AuthorizationServiceConfiguration authorizationServiceConfiguration, @NonNull String client_id, @NonNull Uri redirectUri,boolean useClientSecret){
 
         Map<String, String> additionalParameters=new HashMap<>();
         if(useClientSecret){
             additionalParameters.put("acr_values","3gpp:acr:password");
         }
 
         AuthorizationRequest req = new AuthorizationRequest.Builder(
                 authorizationServiceConfiguration,
                 client_id,
                 ResponseTypeValues.CODE,
                 redirectUri).setScope(SCOPES_DEFUALT)
                 //.setAdditionalParameters(additionalParameters)
                 .build();
         return req;
     }
 
 
 }