2016年12月1日 星期四

openfire 4.3 + converse.js

試了一下 open source 的 IM server/client...
其實基本設定還簡單的呢~

基本配備:

IM server:  openfire
https://www.igniterealtime.org/projects/openfire/

bosh client (html/js) :  conversejs
https://conversejs.org

還要一個讓 client 能跑的 html server : Apache httpd
(httpd server 是也不一定要用 apache,但是因為我的環境有現成的就一直用XD...)

DB : postgresql
資料DB 其實有支援蠻多種的,應該就是 jdbc driver 有的就可以,不過因為我是 postgreql 的支持者,阿就現成的,測試可以用就好...

使用環境:  Windows
是說 openfire 也有 Linux、mac 的版本,不過我是用 window 的就是

=================================================
原本的 openfire 也有附 client,叫 spark,是個原生於 32bit 的 Java swing UI...用 swing我是沒啥意見,但還得限定在 32 bit 上,我就覺得無言了Orz...(其實 openfire 也是 32bit 的,但是可以改成用 64 bit 的 jdk 跑...)

openfire 看起來,也有用 web (html) 的 client,但是,我看他基本上是靠 swf...flash已經死了幾年,就不要再想他了。

所以才選用 其他家的 js client 來試試~

可以參考網路上的文章原始來源:
https://community.igniterealtime.org/docs/DOC-2954
(這篇的 xampp 就也是裝 apache httpd...只是他有順便把 openfire port 轉成 80使用,以方便www上的網路通訊,不過我目前極簡都在 localhost 和內網測,就先不管轉 port的部份)


其實,畫面跟那篇文章差不多,不過,我還是貼一下我的部份(都cut圖了)XD...

================================================
1. 解壓縮 "openfire_4_0_3.zip" (我用zip的,不裝他的 jre)

2. 自己做一個 "run.bat" 放在  openfire\bin
   這個主要是解決,直接按 exe,只能跑 32bit jdk 的問題,內容大概像這樣
D:\jdk1.7.0_79\bin\java -jar ../lib/startup.jar
  
3. 用cmd執行 "run.bat",成功的話,就會這樣
Admin console listening at:
  http://xxxxx:9090
  https://xxxxx:9091

4. link admin console: http://127.0.0.1:9090
   第一次連進來時,會叫你設定server 基本資訊,這招真的超讚,超好心的!!!
   貼幾張過路圖。大概就是要注意:DB 要先開好 database,admin的密碼改了要記好...





5. 檢查 db,應該會生出很多 tables


6. 再用 user/pwd 登入: http://127.0.0.1:9090
   default admin name= admin,去看看 server資訊,跟內容  

7. create New user for test (ex: alex, bob)


   create A room (ex: public)


8. 解壓縮 "converse.js-2.0.2.zip" 到 apache basedoc (www) 下,順便改一下folder name,就是讓他可以 mapping 成  http://apache_server/converse

9. 修改 "converse/index.html"
  在最底下把 bosh_service_url 改成自己的 (如果是要對外在www上使用的話,記得去轉port)
            //bosh_service_url: 'https://conversejs.org/http-bind/', // Please use this connection manager only for testing purposes
            bosh_service_url: 'http://127.0.0.1:7070/http-bind/'  

10. 開幾個 browser: http://127.0.0.1/converse
   用 user/pwd 登入,加入 房間,就可以對談了~可以同時配合 admin 頁面來看一些房間的資訊。




============================================
就先測試一下,基本功能都還蠻容易就會動了~
不過麻,真的要詳細設定跟再客制,就是另一回事了XD...

2016年11月13日 星期日

apacheds API client connect with user/pwd

如果 LDAP server 允許匿名登入的話,連線上只要打 port 之類的就好
ex:
        LdapConnection connection = new LdapNetworkConnection( "127.0.0.1", 10389 );
        connection.connect();

        //do something....
      
        connection.close();

不過如果需要用 user/pwd 登入 的話,那就是要利用 config 連線
http://directory.apache.org/api/user-guide/2.1-connection-disconnection.html
然後就要記得 bind,才能再進行其他的操作
http://directory.apache.org/api/user-guide/2.2-binding-unbinding.html

目前的寫法大概是這樣~
Name: 用dn name 比較沒問題
Credentials: 就是 password...
SslProtocol:apacheDS 提供的SSL是 ldaps:// 協定。沒設定就是一般沒加密連線
(簡易寫法連線,最後面打true,就可以走 ssl)
連線上了之後要 bind...

        LdapConnectionConfig config = new LdapConnectionConfig();
        config.setLdapHost( "localhost" );
        config.setLdapPort( 10389 );
        config.setName( "cn=AddTest11,ou=users,dc=example,dc=com" );
        config.setCredentials( "t123456" );
        config.setSslProtocol("ldaps://");
       
        LdapConnection connection = new LdapNetworkConnection(config);
       
        connection.connect();
        System.out.println("connection="+connection);
       
        connection.bind(config.getName(), config.getCredentials());
       
        if(connection.exists("uid=admin,ou=system"))  {
            System.out.println("true");
        }  else  {
            System.out.println("false");
        }
       
        connection.close();

如果 client 沒有進行 bind,server 端又設定 不能匿名訪問的話,在進行search 操作時,那個 server端會有錯誤訊息XD...但client 是無感的(但是查到的 entry 會是空的,但沒看到exception)...只是理論上看 source code,應該是會丟 LdapNoPermissionException 出來的,不知為啥client沒收到O_oa...

另外理論上,看文件~ 應該是要指定 bind dn,不過好像用 .bind() 也會過~
是說,可以用普通user連線,然後 bind 到 admin,權限可以比較大!(好像sudo一樣XD)
 

2016年11月11日 星期五

apacheDS custom setting and connect with user/password

那個,相信在測試的時後,一直看到 console 叫你改 admin 的密碼~
一定會覺得很煩XD...
如果是透過 studio 的話,就是在這邊,自己來改一改...

不過是說...這個server沒動設定的話,是可以匿名(就是不打user)就連上來~
一樣是感覺非常不安全....

只是,它本身就已經是整個包好的一個 jar 檔,所以只好用 java 直接改寫了~

事先要有 那包完整的 source code(嗯,就是幾十個project 的那個)
不過我也不想改他的 source,因為改了要重包,想到maven 在那邊拼命下載 update 就 覺得人生火花(台語)..好啦,其實我也不會包=.=...也不想包,包壞了debug就累死...
所以我採用外掛取代的方式。source code 是拿來抄跟比對用的(因為文件不可靠阿Q_Q)

這方法,也是 google 到的,不知道算不算爛解(那篇是寫1.5版,method 不同,但作法方向是一樣的,就不po了~),不過我覺得那方向是一個不破壞原本的內容不錯的作法。

1. 改寫 起動 bat (還沒測好前,可以先copy來用就好了,linex 就是改.sh)
apacheds-2.0.0-M23\bin\apacheds.bat
最底下一行
java %ADS_CONTROLS% %ADS_EXTENDED_OPERATIONS% -Dlog4j.configuration="file:../instances/%INSTANCE_NAME%/conf/log4j.properties" -Dapacheds.log.dir=../instances/%INSTANCE_NAME%/log -cp %ADS_CLASSPATH% org.apache.directory.server.UberjarMain ../instances/%INSTANCE_NAME% %ACTION%

把啟動的 main method 改成自訂的 ex:

java %ADS_CONTROLS% %ADS_EXTENDED_OPERATIONS% -Dlog4j.configuration="file:../instances/%INSTANCE_NAME%/conf/log4j.properties" -Dapacheds.log.dir=../instances/%INSTANCE_NAME%/log -cp %ADS_CLASSPATH% xxx.yyy.zzz.MyStart ../instances/%INSTANCE_NAME% %ACTION%


2. copy 一隻自訂的啟動 Java... MyStart
那個 Start Server 很難寫,說真的我也不會啦,但是,有提示跟有 source code...
就是copy  org.apache.directory.server.UberjarMain 一模一樣內容的就對了~
只是改 package 跟 class name ,讓 bat 是用自訂來啟動就是了...

然後找到可以插入設定的程式碼區段,我是把他加在 start 起來後~
    public void start( String instanceDirectory )  {
        InstanceLayout layout = new InstanceLayout( instanceDirectory );

        // Creating ApacheDS service
        service = new ApacheDsService();

        // Initializing the service
        try  {
            LOG.info( "Starting the service." );
            service.start( layout );

            startShutdownListener( layout );
           
            //add my custom
            custom();
        }  catch ( Exception e )  {
            LOG.error( "Failed to start the service.", e );
            stop();
            System.exit( 1 );
        }
    }

在 complire 的時後,我是直接掛 ext lib apacheds-service-2.0.0-M23.jar 上來用,萬一有些還是會對不到的,就是用 eclipse include project 進來處理。
(用 maven 去 下相依的 apachds-all 檔並沒有比較好,抓不到的 class 更多)

3. 寫 自訂的部份~
我有印一些數值,和修改一些安全性設定的部份~
取消匿名訪問,和若是admin 密碼跟預設的一樣,就自己隨便改一下~
(改密碼那段,理論上是應該用 ModificationOperation.REPLACE,不過=.=因為之前測試寫錯了,生了好幾個password 的 attr...就先殺了再建,一次解決)

        DirectoryService ds = this.service.getDirectoryService();

        ds.setAllowAnonymousAccess(false);
        //change admin pwd to avoid some issue
        Dn adminDn = ds.getDnFactory().create( ServerDNConstants.ADMIN_SYSTEM_DN );

        Entry adminEntry = ds.getAdminSession().lookup(adminDn);
        Value<?> userPassword = adminEntry.get( SchemaConstants.USER_PASSWORD_AT ).get();
        boolean needToChangeAdminPassword = Arrays.equals( PartitionNexus.ADMIN_PASSWORD_BYTES, userPassword.getBytes() );
        System.out.println("needToChangeAdminPassword="+needToChangeAdminPassword);
        if(needToChangeAdminPassword)  {
            Modification modify2 = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, "userPassword");
            Modification modify3 = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "userPassword", "123456" );
            ds.getAdminSession().modify(adminDn, modify2, modify3);
            System.out.println("change the password ok.");
        }
              
4. 寫好的Java 內容包成 jar 檔,放到 apacheds-2.0.0-M23\lib 裡
基本上就是那個 lib 會有兩,原本的 apacheds-service-2.0.0-M23.jar 和 自己包的 xxxx.jar

5. 啟動測試~
連線上就改一下


測試時,可以用 studio 建 connection 來試,理論上這樣一改,原本不打user/pwd 的就不行了~只是,還沒key密碼前,server 上的 log 會長很醜就是了...


apacheDS API search, add, modify and delete ( 1.0.0-RC2 )

再來就是寫 client 的部份,嗯~因為懶惰,所以我也順便用同一套的http://directory.apache.org/api/
在此使用的版本是  API 1.0.0-RC2...

看起來都也是剛 release,不過以官網文件程度來說的話,有比 ds 好T_T...雖然也是有點差異,但相比之下,真的是算好的~只是,這文件妙的是,他連之後的功能都先寫上去了!?(不過實際上我都拿最新版的了,還點不出那個 method,或關鍵字眼XD...)
https://directory.apache.org/api/user-guide/2-basic-ldap-api-usage.html

先測一下最常用的查詢,新增,和修改。基本上沒啥太大的問題。
用法原則上就是 建 client,開 connect, 然後操作(操作時會用到一些 cursor,這個用完記得要關),最後就是 close。
大概有些會很常用到的,檢查是否存在(connection.exists),等於是一個 ldap 的search...然後下filiter指定單一項目,不過可以一行就寫出來是很方便的~

建 Entry 時,要加進去的 attribute 跟內容時,可以多利用 studio 防呆做出結構來看,就比憑空想像來的簡單~dn name的一行內容,也可以從studio 的介面看到,較不容易少key層級~

在新增 Entry 時,透過 request, response。就要看response 是否成功,還是得用官方寫法: response.getLdapResult().getResultCode().equals(ResultCodeEnum.SUCCESS)
那個isDefaultSuccess()...目前還不行XD...
是說,目前碰到有出錯之類(建到重覆,改到不存在的...)的,其實都直接是出 Exception...所以,實做去接 exception 做錯誤處理是比較好的~

另外關於要驗證新增後是否成功的那個method,應該就還沒做好(文件上也有寫是 feature啦,不過目前我看不到在那),所以替代方案就是,先 sleep 一下,或是另起 thread 晚一點去確認那個 entry 是否存在了~

修改密碼的話,目前寫進去後,會被default用 ssha hash,

maven dependency
        <dependency>
            <groupId>org.apache.directory.api</groupId>
            <artifactId>api-all</artifactId>
            <version>1.0.0-RC2</version>
        </dependency>

import 使用到的部份
import org.apache.directory.api.ldap.model.cursor.EntryCursor;
import org.apache.directory.api.ldap.model.cursor.SearchCursor;
import org.apache.directory.api.ldap.model.entry.DefaultEntry;
import org.apache.directory.api.ldap.model.entry.DefaultModification;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.entry.Modification;
import org.apache.directory.api.ldap.model.entry.ModificationOperation;
import org.apache.directory.api.ldap.model.message.AddRequest;
import org.apache.directory.api.ldap.model.message.AddRequestImpl;
import org.apache.directory.api.ldap.model.message.AddResponse;
import org.apache.directory.api.ldap.model.message.Control;
import org.apache.directory.api.ldap.model.message.DeleteRequest;
import org.apache.directory.api.ldap.model.message.DeleteRequestImpl;
import org.apache.directory.api.ldap.model.message.DeleteResponse;
import org.apache.directory.api.ldap.model.message.Response;
import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
import org.apache.directory.api.ldap.model.message.SearchRequest;
import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
import org.apache.directory.api.ldap.model.message.SearchResultEntry;
import org.apache.directory.api.ldap.model.message.SearchScope;
import org.apache.directory.api.ldap.model.message.controls.OpaqueControl;
import org.apache.directory.api.ldap.model.name.Dn;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.ldap.client.api.LdapNetworkConnection;


code 的部份(標一下建 connection 和 close 的地方)
        LdapConnection connection = new LdapNetworkConnection( "127.0.0.1", 10389 );
        connection.connect();
        System.out.println("connection="+connection);
       
        //Simple search
        System.out.println("====Simple search");
        EntryCursor cursor = connection.search( "ou=system", "(objectclass=*)", SearchScope.ONELEVEL );

        while ( cursor.next() )  {
            Entry entry = cursor.get();
            System.out.println( entry );
        }
        cursor.close();
       
        //Searching using a DN
        System.out.println("====Dn search");
        Dn systemDn = new Dn( "ou=system" );
        EntryCursor cursor2 = connection.search( systemDn, "(objectclass=*)", SearchScope.ONELEVEL );

        while ( cursor2.next() )  {
            Entry entry = cursor2.get();
            System.out.println( entry );
        }

        cursor2.close();
       
        // Create the SearchRequest object
        System.out.println("====SearchRequest object");
        SearchRequest req = new SearchRequestImpl();
        req.setScope( SearchScope.SUBTREE );
        req.addAttributes( "*" );
        req.setTimeLimit( 0 );
        req.setBase( new Dn( "dc=example,dc=com" ) );
        //req.setFilter( "(objectClass=*)" );  //search all
        req.setFilter( "(ou=users)" );  //assign some

        // Process the request
        SearchCursor searchCursor = connection.search( req );

        while ( searchCursor.next() )  {
            Response response = searchCursor.get();

            // process the SearchResultEntry
            if ( response instanceof SearchResultEntry )  {
                Entry resultEntry = ( ( SearchResultEntry ) response ).getEntry();
                System.out.println(resultEntry);
            }
        }
        searchCursor.close();
       
        System.out.println("======Test Search End========");
        System.out.println("======START to UPDATE");
        String uname1="AddTest11";
        Entry entry1 = new DefaultEntry(
                "cn="+uname1+",ou=users,dc=example,dc=com",
                "ObjectClass: top",
                "ObjectClass: inetOrgPerson",
                "ObjectClass: person",
                "ObjectClass: organizationalPerson",
                "cn: "+uname1,
                "sn: "+uname1 );
        if(!connection.exists("cn="+uname1+",ou=users,dc=example,dc=com"))  {
            AddRequest addRequest = new AddRequestImpl();
            addRequest.setEntry( entry1 );
            AddResponse response = connection.add( addRequest );
            System.out.println(response.getLdapResult().isDefaultSuccess());  //why this is false ?_?a...bug?
            if( response.getLdapResult().isDefaultSuccess()
                    || response.getLdapResult().getResultCode().equals(ResultCodeEnum.SUCCESS))  {
                System.out.println("Add OK");
            }  else  {
                System.out.println("not default success["+response.getLdapResult().getResultCode()+"]:"+response.getLdapResult().getDiagnosticMessage());
            }
        }
        //check exist? check it after wait some while
        Thread.currentThread().sleep(1000);
        if(connection.exists("cn="+uname1+",ou=users,dc=example,dc=com"))  {
            System.out.println("re check add OK");
        }
       
        //https://directory.apache.org/api/user-guide/2.6-modifying.html
        //modify
        Modification modify1 = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "uid", "testuser" );
        Modification modify2 = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "givenName", "Well", "Smile" );
        Modification modify3 = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "userPassword", "t123456" );
        connection.modify( "cn="+uname1+",ou=users,dc=example,dc=com", modify1,  modify2, modify3);
       
        System.out.println("======START to Delete");
        //delete easy
        connection.delete( "cn=AddTest2,ou=users,dc=example,dc=com" );
       
        //delete by repsonse
        DeleteRequest deleteRequest = new DeleteRequestImpl();
        deleteRequest.setName( new Dn( "cn=AddTest3,ou=users,dc=example,dc=com" ) );
        Control deleteTreeControl = new OpaqueControl( "1.2.840.113556.1.4.805" );
        deleteRequest.addControl( deleteTreeControl );
        DeleteResponse deleteResponse = connection.delete( deleteRequest );
        if( deleteResponse.getLdapResult().isDefaultSuccess()
                || deleteResponse.getLdapResult().getResultCode().equals(ResultCodeEnum.SUCCESS))  {
            System.out.println("Delete OK");
        }  else  {
            System.out.println("delete fail["+deleteResponse.getLdapResult().getResultCode()+"]:"+deleteResponse.getLdapResult().getDiagnosticMessage());
        }
       
        connection.close();

2016年11月10日 星期四

ApacheDS (apacheds-2.0.0-M23)

雖然 studio 看起來很方便,不過實際應用上,是不太會那樣子用啦一.一a...
不過把他當做一個 UI/Manager/Client 之類的,應該是還不錯....

其實重點是要試單純的這個 ApacheDS ~囧/
http://directory.apache.org/apacheds/
要非常注意在使用的版本,因為麻...現在是一個非常不穩定的版本樣子,拿官網上的範例貼全都會有問題(連package 都搬家了,class name/method 改名(還好勉強可以看出一點端倪,關鍵字還有),看文件簡直是猜猜樂~你說呢|||Orz...)...想起以前去拿 hadoop 1.0 剛出來時,也是超級白老鼠,連default跑起來都有問題T_T...

這包的下來,基本上就是一個完整的 osgi server...
因為用途的關係,我直接用 zip...
http://directory.apache.org/apacheds/downloads.html

Download Archive zip/tar.gz
Download Download Sources

(source code 解開後,是很大包的 maven project set,唉,雖然現在的project都弄成這麼複雜,不過說真的 import 起來是相當的方便就是~不過因為他這版本功能不穩定,所以 source code 是非常需要的,除非剛好裡面的你都能用,完全不客制...)

把 zip 解開就是一個 osgi server...
執行
apacheds-2.0.0-M23\bin\apacheds.bat
就很快樂的跑起來(都不打參數,就是 default instance start)...
有興趣的就去看看他的 shell 檔在寫什麼就知道
console 上會一直提醒,要去改安全性...不過因為是 init,所以先試著做完設定後再關起來吧~

然後可以去看他資料夾底下,開始有生資料出來了,不然一開始超空的!只有資料夾結構~
apacheds-2.0.0-M23\instances\default\**
看資料夾就也蠻好認的就是, 通常就是去看 log..log是用log4j,設定檔是放在  conf 下~
partition 裡就是重要的實體資料檔。聽說可以用 copy的,原本想去把 studio 裡 server的資料 copy過來用,懶得再建,但發現 studio 裡的 檔名路徑長度超過了 win 的長度...GG...只好乖乖的再重打...

他 instance 是可以指定的,如果 instance 不存在的話,

就會建一組 default 設定起來,然後在檔案結構下多一個資料夾,蠻好區分的,只是就是之後打啟動指令,要指定 instance 的名稱,ex:
 apacheds-2.0.0-M23\bin\apacheds.bat test1
另外就是,資料夾生出來後,要自己手動去 copy 一下 log4j.properties,可以直接從 default 的 conf 那邊 copy過來就好了...反正他會吐訊息出來,所以倒也還好找~是說他就也會忽略這問題,然後就不寫log了....


然後當然是用 studio 來連一下
LDAP -> New Connection
建一個自己設定的 Connection...然後因為再那邊東按西按,已經建好了就是這樣一x一|||
(一開始打錯,也可以在去 connection 的 properties 改一改重連就可以)

沒透過修改的話,原ApacheDS的設定就是
port 開 10893
 還有因為好像這版沒有 default 的 admin 密碼,所以就是先用不認證的方式進來改 admin...

連接成功後,就可以看到內容了~
基本上除了建 partition 很有問題外~建人跟底下的項目,測試起來是還ok啦。
(這項應該就是 studio 的 問題,他常在寫 conf 時會出錯,但是要修正也是以後的事了@@,反正只是 client 的關係,這邊是 server,所以就先當client的問題不是問題)

另外 studio 配的 ApacheDS 的版本也是有配套限制的~
當下因為看 studio M10 有些問題,想說studio 退版,拿到M8的(不知道為啥沒看到 M9),connection 馬上 GG...所以還是就先目前的配套將就使用...
(是說,連安裝包的樣式看起來好像也不太一樣,應該是有大改)

是說 studio M10 是,也有點OX,他目前裡面的 servers 只能內建,不能指定外server,bug也一大堆(虧他上面還標啥最好的應用之類的),只能說還不成熟,只是在開發時,加減用應該也是可以...(工程師的一堆莫名成就感就來自這種有的沒的問題,就當增加信心吧Orz...)

正常的 shutdown ,應該是可以透過 cmd 來下的~
 apacheds-2.0.0-M23\bin\apacheds.bat test1 stop
或是 在原本的 console 上 ctrl+c 也可以~

總之,只要原本的 console 停下後就是有正常 shutdown了~

其指令,預設就是,第一個參數 是 instance name(folder name),第二個是行為
有 start/stop/repair...(是說怎麼知道的,就是看到 source code 才知道的阿Orz..)

至於指令明明是下 stop...但看到echo start 嗯,就不要研究這麼多了,工程師在趕時間的時後,都會出現很多奇妙的東西!



2016年11月8日 星期二

some develop tool on mac

最近在重新整理mac上的東西~也重裝了一些,整理一下~

===JAVA===
基本上java派的,ide 幾乎都是 Eclipse...就沒啥好說的...
(不過我的 java 跟 server 都是在 windows上面~mac不太想弄那麼雜的環境...反正要各種環境,開windows就有了=.=a)


===komodo edit===
然後如果是要寫其它的language...就會用 komodo edit...個人主要是用在寫純網頁應用(html/js/css)的部份~(雖然踏坑時,當年只是為了寫一隻py..囧/)
komodo ide 是要錢的付費版,不要找錯了XD...
https://www.activestate.com/komodo-edit

理論上,他們家的官網好像在這裡?!
https://www.activestate.com/komodo-ide/downloads/edit
(總之,就是進去沒有試用天數,不用授權的那版就是open source版...不過我通常都不是在這邊下的=.=a)

真的去open source 上找,都是放source,要自己包成 application 是真的有困難,所以大概都是用google 關鍵字找載點,從比較有名氣的站下來的,應該就比較沒問題~(是說,我自己就是一個較早的版本,然後到處裝,反正他有內建自動升級...不過說真的,他不同版本,有時後讀同一檔,顯示自動tab 縮排,跟tab 上是有點不相容的地方...會跑版=.=|||...所以總之,我就僅量一個komodo專案就固定在某台機子上寫就好~囧/)





===FTP/SFTP client===
FTP client 上傳,習慣就是用 filezilla client...
https://filezilla-project.org/download.php
只是有點煩人的就是~小紅傘會一直把他列入觀查名單內...看到常會緊張一下Q_Q...(不過後來就想說,反正真的要是中槍,也不只我一個!)


===git=== 
然後在想要裝 git 的時後,看到了這個
https://www.sourcetreeapp.com/

同時支援 mac 和 windows...這東西看起來很新!copyright 掛在2016...

看這應該就是和 bitbucket 合作的那間公司(atlassian)關係出品~
雖然是降子,不過他連線上也可以選用 github 的帳號~
看起來是可以加多個帳號~

不過因為我習慣用private,所以github一直不是我的菜XD...反正以後真的有需要用到再說吧~(我都常跟大家說,私人小小案可以搬家到這邊來,反正有local git,要再放到 remote git 是件很容易的事~)

其介面的內容,比我之前用的 git小烏龜來說,資訊多多了:)...
(是說 小烏龜系列,我覺得除了他原本的版控功能,其最好用的就是,可以隨便選兩個檔案就右鍵單純diff...在比對檔案時很方便~還不用搞 notepad++ 的 plugin)

Apache Directory Studio - add partition and user

在 blog 上直接用 貼圖的方式,似乎圖檔使用空間太大了..不過我又懶得一張一張存XD..會讓文章存不進去,就分幾段來好了@@~

練習加一個 partition,要先把 server停下來,
從server 那邊點 連線 右鍵 open config ,切到 partition 加一個...然後 ctrl+s
(server online 時是可以編,但是是存不進去的!)
這應該是個bug,但是...看起來他寫下一版才要修正Orz...
http://osdir.com/ml/dev-directory-apache/2016-01/msg00118.html



這邊存了之後,要記得再重開這server的 conf檔看,是不是真的有寫進去,總之就覺得這邊怪怪的,我save了很多次,才真的寫進去了=.=?

然後再重起 server,建連線,看一下是不是被加進去了~
 

來建 unit ,大概就都是 Entry 的範圍


New Entry 有兩種

Default 的不會帶 domain(不過要加,就是在這邊都選進來加),在下一步時,選 organizationUnit  Add(如果已經被加過去後, avaiable object 就查不到了~)


再來輸入 RDN,看一下 parent 有沒有選錯,這邊還可以改~


下一步,確認ok就 Finish,就加進去了~

然後總算可以加人了...一樣 New Entry,Object Class 選 inetOrgPerson



在這裡輸入 RDN


下一步後,還要再打 sn ...沒打後面會出錯QQ..
 

Finish 沒出事的話,就加進去了



這樣,人員就加成功了!

然後因為人總是要有個帳號的,所以就在這個人的資料(右鍵選單)上再加屬性


這個蠻貼心的,會自動過濾列出來(有防呆很適合我這種半路出家的QQ),其實右邊也有下拉選單可以選~



 然後就會生出一個 attribute ,可以輸入內容了~



打好後 ctrl+s ,再來回切換一下確認(前面他 config 都怪怪的,總覺得不太安心XD)

有帳號就要有密碼,一樣加 attribute: userPassword


 如果之後的都下一步,不輸入的話,就會變成,不用密碼~
是說,不知道  option 在做啥, 看教學似乎沒這東西,就先空的跳過到

這邊如果以後要改,可以再透過這種方式回來加


Finish 後又不輸入密碼,就會是空的!



是說,沒密碼很危險,還是來改一下吧~

輸入密碼,提供不少的加密方式,先基本的,然後為了不要忘記打了什麼(測試的東西,老是一大堆)把底下的 框 勾起來,就可以看到了XD,預設是沒勾的,就會看到很多黑點~(給正常使用者用的時候QQ)


 OK 後就可以看到資料(還不錯啦,沒有直接都亮給你看XD)


最基本的人員加入就完成~