2016年5月19日 星期四

【JAVA】LDAPS整合AD驗證

參考來源:ActiveDirectoryAuthentication
原作者是使用ldap,下面修改為ldaps驗證
為了安全考量,有一份堅持,
原作者是用nsLookup去取得AD的主機列表,
下面是先hardcode加上一台AD主機位址,並且加上憑證
當然憑證要匯到JDK的ca路徑
範例網域:contoso.com,當然要換成你要用的Domain


package com.uitox.shared.util;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.security.auth.login.AccountException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;

public class ActiveDirectoryAuthentication {
 private static final String CONTEXT_FACTORY_CLASS = "com.sun.jndi.ldap.LdapCtxFactory";

 private String ldapServerUrls[]={"ldap://fdc.contoso.com:636"};

 private int lastLdapUrlIndex;

 private final String domainName;

 public ActiveDirectoryAuthentication(String domainName) {
  this.domainName = domainName.toUpperCase();

  try {
//   ldapServerUrls = nsLookup(domainName);  
  } catch (Exception e) {
   e.printStackTrace();
  }
  lastLdapUrlIndex = 0;
 }

 public boolean authenticate(String username, String password)
   throws LoginException {
  if (ldapServerUrls == null || ldapServerUrls.length == 0) {
   throw new AccountException("Unable to find ldap servers");
  }
  if (username == null || password == null
    || username.trim().length() == 0
    || password.trim().length() == 0) {
   throw new FailedLoginException("Username or password is empty");
  }
  int retryCount = 0;
  int currentLdapUrlIndex = lastLdapUrlIndex;
  do {
   retryCount++;
   try {
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, CONTEXT_FACTORY_CLASS);
    env.put(Context.PROVIDER_URL,
      ldapServerUrls[currentLdapUrlIndex]);
    env.put(Context.SECURITY_PROTOCOL, "ssl");

    System.setProperty("javax.net.ssl.trustStore","/jre/lib/security/cacerts");
    System.setProperty("javax.net.ssl.trustStorePassword","changeit");

    env.put(Context.SECURITY_PRINCIPAL, username + "@" + domainName);
    env.put(Context.SECURITY_CREDENTIALS, password);
    DirContext ctx = new InitialDirContext(env);
    ctx.close();
    lastLdapUrlIndex = currentLdapUrlIndex;
    return true;
   } catch (CommunicationException exp) {
    // TODO you can replace with log4j or slf4j API
    exp.printStackTrace();
    // if the exception of type communication we can assume the AD
    // is not reachable hence retry can be attempted with next
    // available AD
    if (retryCount < ldapServerUrls.length) {
     currentLdapUrlIndex++;
     if (currentLdapUrlIndex == ldapServerUrls.length) {
      currentLdapUrlIndex = 0;
     }
     continue;
    }
    return false;
   } catch (Throwable throwable) {
    throwable.printStackTrace();
    return false;
   }
  } while (true);
 }

 private static String[] nsLookup(String argDomain) throws Exception {
  try {
   Hashtable env = new Hashtable();
   env.put(Context.INITIAL_CONTEXT_FACTORY,
     "com.sun.jndi.dns.DnsContextFactory");
   env.put("java.naming.provider.url", "dns:");
   DirContext ctx = new InitialDirContext(env);
   Attributes attributes = ctx.getAttributes(
     String.format("_ldap._tcp.%s", argDomain),
     new String[] { "srv" });
   // try thrice to get the KDC servers before throwing error
   for (int i = 0; i < 3; i++) {
    Attribute a = attributes.get("srv");
    if (a != null) {
     List domainServers = new ArrayList();
     NamingEnumeration enumeration = a.getAll();
     while (enumeration.hasMoreElements()) {
      String srvAttr = (String) enumeration.next();
      // the value are in space separated 0) priority 1)
      // weight 2) port 3) server
      String values[] = srvAttr.toString().split(" ");
      domainServers.add(String.format("ldap://%s:%s",
        values[3], values[2]));
     }
     String domainServersArray[] = new String[domainServers
       .size()];
     domainServers.toArray(domainServersArray);
     return domainServersArray;
    }
   }
   throw new Exception("Unable to find srv attribute for the domain "
     + argDomain);
  } catch (NamingException exp) {
   throw new Exception("Error while performing nslookup. Root Cause: "
     + exp.getMessage(), exp)
  }
 }
}
主要改造說明
  1. ldapServerUrls直接加入主機 22行處改成,加上DC主機,ex:ldap://fdc.contoso.com:636
    
     private String ldapServerUrls[]={"ldap://fdc.contoso.com:636"};
    
    註解掉原nsLookup查表,因為我hardcode了 XD
  2. 指定憑證CA檔 先將企業內部root CA匯入,至/jre/lib/security/cacerts
    然後指定CA檔,讓java知道就行了
    
        System.setProperty("javax.net.ssl.trustStore","<JDK ROOT>/jre/lib/security/cacerts");
        System.setProperty("javax.net.ssl.trustStorePassword","changeit");
    
最後,在寫一個驗證的Class,作登錄就大功告成。

public class UserCredentialManager {
        ...
 public synchronized void login(String name, String password){
  boolean IsAuth = false;
  ActiveDirectoryAuthentication ADAuth = new ActiveDirectoryAuthentication("CONTOSO.COM");
  try {
   IsAuth = ADAuth.authenticate(name, password);
  } catch (LoginException e) {
   e.printStackTrace();
  }
  
  if(IsAuth == true){
   user = name;
  }
  
 }
        ...
}

2015年3月6日 星期五

[centos]sudoers檔案權限 os版本差異

 ]$ sudo su -
sudo: /etc/sudoers is mode 0600, should be 0440
sudo: no valid sudoers sources found, quitting

不同版本,略有差異
當centos = 6.3
sudoers file mode 440
其餘centos >6.3
sudoers file mode 600

sudoer主檔、與include的file (/etc/sudoers.d/)皆要變更權限

2010年12月29日 星期三

[nagios]Nagios Plugin for Cacti Troubleshooting

用最新版的ndoutils-1.4b9 + npc v2.04不相容


Cacti: 0.8.7e
Cacti plugin npc: v2.04
nagios:v3.23
ndoutils:v1.4b9
如果用上面的組合,在計分版上會抱蛋


在/var/log/message會出現MySql的錯誤,表格根本對不起來
cacti ndo2db-3x: mysql_error: 'Unknown column 'long_output' in 'field list''
我看了一下npc v2.04是2009版的
2009-06-22 - 2.0.4 release notes:

,而我的ndoutils是最新版的v1.4b9
再去看ndoutils的版本 
所以當然要抓開發者,在開發時的ndoutils版本
終於解了這個問題~
這個「看release notes的好習慣」,是向dlink廠商學習的~
果然有效~

2010年12月23日 星期四

VirtualBox 的硬碟檔複製

為了要玩雲端,一次要搞四台 VM,看網路上的文章,使用 VBoxManage.exe clonevdi 這個指令來進行 HardDisk 複製,因為 VDI 檔是帶有 UDDI 的。

因為我要在 Ubuntu 10.04 下使用。一開始,因為找不到 VBoxManage 這個指令,就用 cp 複製囉!但要透過 VirtualBox 的虛擬媒體管理員加入硬碟時,會出現錯誤訊息。

還真是一個頭兩個大耶!又沒有 vboxmanage 這個指令,到底要怎麼搞呀?只好再上網找解決之道囉!

哈!原來我的指令打錯了,大小寫是有差的,VBoxManage 這個指令才存在啦!Orz

不過,既然我都已經複製了,總不能浪費這個 vdi 檔吧!幸好找到了篇文章,執行了下列指令來改變 UUID,就 OK 啦!

$ VBoxManage internalcommands setvdiuuid hdp1.vdi
Oracle VM VirtualBox Command Line Management Interface Version 3.2.10
(C) 2005-2010 Oracle Corporation
All rights reserved.

UUID changed to: 302a4a36-ee6f-47d6-ac28-45fa06beca95

複製 vdi 檔的指令,當然也要記錄一下囉!

$ VBoxManage clonevdi hdp0.vdi hdp2.vdi
Oracle VM VirtualBox Command Line Management Interface Version 3.2.10
(C) 2005-2010 Oracle Corporation
All rights reserved.

0%...10%...20%...30%....40%...50%...60%...70%...80%...90%...100%
Clone hard disk created in format 'VDI'. UUID: 3704dd76-0bf1-4f0e-a201-ba3f70a05eb6

Help 檔沒找到這兩個參數,可能是版本的關係吧?但還是可以執行。

2010年12月17日 星期五

RHEL6+KVM Guest OS bridge with Host nics

1.首先要把很難用的NetworkManager服務停掉,換回熟悉的network
# chkconfig NetworkManager off
# chkconfig network on
# service NetworkManager stop
# service network start
2.Host實體介面的ifcfg-*,擺脫NetworkManger的控制
ifcfg-eth*
   NM_CONTROLLED=no
3.我們用eth0示範bridge功能,在此bridge的device將取名為br0,先修改eth0的設定
BOOTPROTO=none 
BRIDGE=br0
#eth0本來的ip設給br0
4.新增ifcfg-br0設定如下
DEVICE=br0
TYPE=Bridge
BOOTPROTO=static
ONBOOT=yes
DELAY=0
IPADDR=192.168.1.x
5.防火牆設定值修改
# iptables -I FORWARD -m physdev --physdev-is-bridged -j ACCEPT
# service iptables save
# service iptables restart
6.重載libvirt設定
service libvirtd reload
7.最後可以看一下bridge的設定有沒有生效

# brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.000e0cb30550       no              eth0
8.再來修改guest os的網路設定,就會看到新建的bridge interface了
http://www.techotopia.com/index.php/Creating_an_RHEL_6_KVM_Networked_Bridge_Interface
9.官方文件有說 另一個內建的virbr0是拿來做NAT的,請大家不要亂搞它XD

Ref: Redhat Docs

2010年12月16日 星期四

[Life]下雨天不用帶手套

就在今天,才發現雨衣有手套的功能。今天超冷的~cool~又下雨,如果帶上手套,沒兩三下就泡水了,意外發現手的內裡的縫一個圈圈,奇怪又沒有鈕扣,不知做甚麼用。結果用大拇指,


我的疑問沒了,這天德牌雨衣,穿了幾年了,同事都不知道走了多少,現在才知道他的功用,這樣的話,雨衣就會緊靠手背,寒風吹過來就可以幫你擋風擋雨,太貼心的設計~

2010年12月13日 星期一

[Cacti]CentOS與Cacti的Gap

上個星期與Cacti的Gap終於解開了
我的Cacti是安裝在CentOS上,圖片會斷斷續續的,剛開始真得是疑東疑西的,會不會是我的PHP版本問題呢?還是我的測試環境太亂了?於是乎我又裝了一台~The Same,這款ㄟ代誌那A花生~~因為我上上上個月,才在RedHat上安裝過,一直很順。
在我新裝好另一台後~A Miracle Happened ~~好加在我的時間差很多,我已經先在未來的時間畫圖出來了,我一下ntpdate之後,圖都出不來了,要等到那個時間過後,我的圖才會往後畫,很明顯是時間差問題,這就是Cacti跟CentOS的Gap,不過這也要裝在VM上才會有問題。
因為Centos kernel的參數issue,CentOS用的kernel是1000Mhz clock,把它改成100Mhz clock就OK了
參考:http://forums.cacti.net/about29252.html
作法如下:
安裝kernel-vm套件,用這個Kernel來開機
STEP1:編輯yum的repo檔,如/etc/yum.repos.d/CentOS-Base.repo加上下面這個站點
]# vi /etc/yum.repos.d/CentOS-Base.repo
--||code||--
[testing]
name=CentOS Testing

baseurl=http://dev.centos.org/centos/$releasever/testing/$basearch/
enabled=0
gpgcheck=1
gpgkey=http://dev.centos.org/centos/RPM-GPG-KEY-CentOS-testing
 --||code||--


STEP2:用yum更新
]# yum install kernel-vm --enablerepo=testing


STEP3:修改GRUB開機檔
]# vi /boot/grub/menu.lst
把default值改在新的kernel(結尾為vm)


STEP4:重開機,讓CentOS用新的kernel work