Classic to xPages (вызов из классического приложения)

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 980
611
BIT
420
в процессе перевода приложения на xPages возникает законный вопрос - как оставить временно живущим "классический" код?
схема следующая (на примере агента): Агент->обертка вызова по http->профит
пример агента
Java:
import lotus.domino.*;

public class JavaAgent extends AgentBase {

    public void NotesMain() {

      try {
          Session ses = getSession();
          AgentContext agentContext = ses.getAgentContext();

          // (Your code goes here)
          com.setralubs.XAgent.run(ses, agentContext, "test", "");//".castrolcis.com");

      } catch(Exception e) {
          e.printStackTrace();
       }
   }
}
обертка
Java:
import lotus.domino.Session;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import lotus.domino.AgentContext;
import lotus.domino.Database;
import lotus.domino.Name;


public class XAgent {


    public static void run(Session ses, AgentContext agentContext, String xpageName, String domain) {
        String url = null;
        try {
            TrustAllCertificates.install();
            LtpaToken ltpaToken=new LtpaToken();
            ltpaToken.initByConfiguration(ses);
            String token=ltpaToken.generateLtpaToken(ses.getEffectiveUserName());
            Database db=agentContext.getCurrentDatabase();
            String dbPath = agentContext.getCurrentDatabase().getFilePath();
            String server=db.getServer();
            //dbPath=db.getHttpURL();
            //System.out.println("path->"+dbPath);
            if (domain.isEmpty())domain=ltpaToken.getDomain();
            Name name=ses.createName(server);
            server=name.getCommon();
            url = "https://"+server+domain+"/" + dbPath + "/" + xpageName + ".xsp";
            System.out.println("Starting " + xpageName + " in database " + dbPath);
            System.out.println("URL->"+url);
            String cookies="LtpaToken=" + token;// + "; domain=" + domain.substring(1) + "; path=/";
            System.out.println("Cookies->"+cookies);

            URL xPageURL = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) xPageURL.openConnection();
            conn.setRequestProperty("Cookie", cookies);
            //conn.connect();

            switch (conn.getResponseCode()) {
            case HttpURLConnection.HTTP_OK:
                // read from the urlconnection via the bufferedreader
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    System.out.println("Response: " + line);
                }
                bufferedReader.close();

                break;
            case HttpURLConnection.HTTP_INTERNAL_ERROR:
                System.out.println("Interal server error while running");
                break;
            default:
                System.out.println("An error occurred: " + conn.getResponseCode());
                System.out.println("Error message: " + conn.getResponseMessage());
                break;
            }

            conn.disconnect();

            System.out.println("Finished " + xpageName + " in database " + dbPath);

        } catch (Exception e) {
            System.out.println("URL->"+url);
            e.printStackTrace();
        }
    }
}
увидим знакомы (по моим постам) вызовы классов TrustAllCertificates.install(); LtpaToken ltpaToken...
класс токена расширил получением домена из дока сайта
Java:
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
//import java.util.Calendar;
//import java.util.Date;
import java.util.GregorianCalendar;

import javax.xml.bind.DatatypeConverter;

import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.NotesException;
import lotus.domino.Session;
import lotus.domino.View;

/*
* @author Serdar Basegmez, Developi (http://lotusnotus.com/en)
*/

public class LtpaToken{

  public static final String NAMESDB="names.nsf";
  public static final String SSOVIEW="($WebSSOConfigs)";
  public static final String SSO_DOMINO_SECRETFIELD="LTPA_DominoSecret";
  public static final String SSO_DOMINO_DURATIONFIELD="LTPA_TokenExpiration";
  public static final String SSO_DOMINO_DOMAIN="LTPA_TokenDomain";
  private String WebSSOSite="CRUINTERNET:CISsite";
  private boolean ready=false;

  private int duration=300;
  private String ltpaSecret="";
  private String classID;
  private String domain="";

  public String getDomain() {
    return domain;
}


public void setDomain(String domain) {
    this.domain = domain;
}


public LtpaToken(){
      classID="::"+this.getClass().getName()+"::";
      System.out.println("constructor:" + this.getClass().getName());
  }


  public LtpaToken(String ltpaSecret) {
    this();
    setLtpaSecret(ltpaSecret);
  }

  public LtpaToken(String ltpaSecret, int duration) {
    this();
    setLtpaSecret(ltpaSecret);
    setDuration(duration);
  }

  public void initByConfiguration(Session session) throws Exception{
    initByConfiguration(session, WebSSOSite);
  }

  public void initByConfiguration(Session session, String configName) throws Exception {
    Database dbNames=null;
    View ssoView=null;
    Document ssoDoc=null;
    String memberID=classID+"initByConfiguration::";
    String status="try...";
    try {
      if (session==null)throw new Exception("session is null");
      Database db=session.getCurrentDatabase();
      if (db==null)throw new Exception("current db is null");
      String currentServer=db.getServer();//session.getServerName();
      db.recycle();
      status="get server name";
  
      status="get NAB from:"+currentServer;
      dbNames=session.getDatabase(currentServer, NAMESDB, false);
      status="get view"+SSOVIEW;
      ssoView=dbNames.getView(SSOVIEW);
      status=currentServer+"->get config doc:"+configName;
      ssoDoc=ssoView.getDocumentByKey(configName, true);
      if(ssoDoc==null) {
        status="Unable to find SSO configuration with the given configName.";
        throw new IllegalArgumentException(status);
      }
  
      setLtpaSecret(ssoDoc.getItemValueString(SSO_DOMINO_SECRETFIELD));
      setDuration(ssoDoc.getItemValueInteger(SSO_DOMINO_DURATIONFIELD));
      setDomain(ssoDoc.getItemValueString(SSO_DOMINO_DOMAIN));
      status="success";
  
    } catch (NotesException ex) {
      status = "Notes exception:"+ex.text;
      throw new Exception("Notes Error: "+ex);
    } finally {
      try {
    
        if(dbNames!=null) dbNames.recycle();
        if(ssoView!=null) ssoView.recycle();
        if(ssoDoc!=null) ssoDoc.recycle();
        System.out.println(memberID+status);
      } catch(NotesException exc) {
        System.out.println(memberID+"finally catch:"+status);
        //ignore
      }
    }
  }

  public String generateLtpaToken(String userName) {
    String memberID=classID+"generateLtpaToken";
    if(!isReady()) {
      throw new IllegalStateException("LtpaGenerator is not ready.");
    }

    MessageDigest sha1 = null;
    //Calendar ci=Calendar.getInstance();
    GregorianCalendar creationDate=new GregorianCalendar();
    GregorianCalendar expiringDate=new GregorianCalendar();

    byte[] userNameArray=userName.getBytes();

    expiringDate.add(GregorianCalendar.MINUTE, duration);

    System.out.println(memberID+"Ltpa creation:"+creationDate.getTime().toString());
    System.out.println(memberID+"Ltpa expiring:"+expiringDate.getTime().toString());

    try {
      sha1 = MessageDigest.getInstance( "SHA-1" );
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace(System.err);
    }
    
    byte[] secretDecoded=DatatypeConverter.parseBase64Binary(ltpaSecret);

    // Look at important notes above...
    try {
      if(Charset.isSupported("LMBCS")) {
        userNameArray=userName.getBytes("LMBCS");
      }
    } catch (UnsupportedEncodingException e) {
      // Not supposed to fall here.
    }
  
    byte[] tokenBase=concatBytes(("\000\001\002\003"+getHexRep(creationDate)+getHexRep(expiringDate)).getBytes(), userNameArray);

    byte[] digest=sha1.digest(concatBytes(tokenBase, secretDecoded));

    return DatatypeConverter.printBase64Binary(concatBytes(tokenBase, digest));
  }



  public static byte[] concatBytes(byte[] arr1, byte[] arr2) {
    byte[] result=Arrays.copyOf(arr1, arr1.length+arr2.length);
    System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
    return result;
  }

  public static String getHexRep(GregorianCalendar date) {
    int timeVal=(int)(date.getTimeInMillis()/1000);
    String hex=Integer.toHexString(timeVal).toUpperCase();

    if(hex.length()>=8) {
      return hex;
    } else {
      return String.format("%0"+(8-hex.length())+"d", new Integer[]{new Integer(0)})+hex;
    }
  }

  public void setDuration(int duration) {
    this.duration = duration;
  }

  public void setLtpaSecret(String ltpaSecret) {
    this.ltpaSecret = ltpaSecret;
    this.ready=true;
  }

  public boolean isReady() {
    return ready;
  }

  public String test(String param){
      return "test:" + param;
  }
  public static void main(String[] args) {
      // TODO Auto-generated method stub

  }

}
можно былобы и из LS2J, если бы не необходимость Session или придется мудрить с промежуточным xPage и шифрованием как уже описывал в Унификации
агент, скорее-всего, нужно будет запускать с правами подписывающего или того кто имеет доступ к Ltpa...
Чтобы код хэпаги исполнялся от имени к-л пользователя - можно предусмотреть вызов агента с контекстным документом (где и брать юзера) и передавать доп. параметр в обертку
 
Последнее редактирование:
  • Нравится
Реакции: RocketCoon и Vertigo

lmike

нет, пердело совершенство
Lotus Team
27.08.2008
7 980
611
BIT
420
В куках я закоментил часть - эта часть вызывала ошибку 500, ругань в логах:
java.lang.IllegalArgumentException: Cookie name "domain" is a reserved token
выяснять причину отличия поведения от xPages я не стал
полагаю будет лишним упоминать - без кукисов, будет запрос авторизации (если страница не анонимная)
 
  • Нравится
Реакции: rinsk и Vertigo
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!