Add internal token authorization mechanism

This commit is contained in:
mag 2015-05-15 14:14:29 +08:00
parent efeb6993a4
commit 1fdc46c677
10 changed files with 230 additions and 21 deletions

View file

@ -26,6 +26,8 @@ import java.util.Map;
public class IPAuthenticationFilter implements Filter{ public class IPAuthenticationFilter implements Filter{
private static final Logger logger = LoggerFactory.getLogger(IPAuthenticationFilter.class); private static final Logger logger = LoggerFactory.getLogger(IPAuthenticationFilter.class);
DynamicStringProperty ipUserStr = DynamicPropertyFactory.getInstance().getStringProperty("ip.authentication", "127.0.0.1,172.16.144.61=releaseSys"); DynamicStringProperty ipUserStr = DynamicPropertyFactory.getInstance().getStringProperty("ip.authentication", "127.0.0.1,172.16.144.61=releaseSys");
private static final String SLB_SERVER_USER = "slbServer";
public static final String SERVER_TOKEN_HEADER = "SlbServerToken";
private volatile Map<String, String> ipUserMap = new HashMap<>(); private volatile Map<String, String> ipUserMap = new HashMap<>();
@ -52,18 +54,32 @@ public class IPAuthenticationFilter implements Filter{
return; return;
} }
// check whether it is called from other slb servers.
String slbServerToken = request.getHeader(SERVER_TOKEN_HEADER);
if (slbServerToken != null){
if (TokenManager.validateToken(slbServerToken)){
setAssertion(request, SLB_SERVER_USER);
filterChain.doFilter(request,response);
return;
}
}
// if the request is from in ip white list, then authenticate it using the ip white list. // if the request is from in ip white list, then authenticate it using the ip white list.
String clientIP = getClientIP(request); String clientIP = getClientIP(request);
String ipUser = getIpUser(clientIP); String ipUser = getIpUser(clientIP);
if (ipUser != null){ if (ipUser != null){
logger.info("Authenticated by IP: " + clientIP + " Assigned userName:" + ipUser); logger.info("Authenticated by IP: " + clientIP + " Assigned userName:" + ipUser);
assertion = new AssertionImpl(ipUser); setAssertion(request, ipUser);
request.setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION, assertion);
request.getSession().setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION, assertion);
} }
filterChain.doFilter(request,response); filterChain.doFilter(request,response);
} }
private void setAssertion(HttpServletRequest request, String userName) {
Assertion assertion = new AssertionImpl(userName);
request.setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION, assertion);
request.getSession().setAttribute(AbstractCasFilter.CONST_CAS_ASSERTION, assertion);
}
@Override @Override
public void destroy() { public void destroy() {
// nothing to do // nothing to do

View file

@ -0,0 +1,109 @@
package com.ctrip.zeus.auth.impl;
import com.ctrip.zeus.dal.core.AuthPrivateKeyDao;
import com.ctrip.zeus.dal.core.AuthPrivateKeyDo;
import com.ctrip.zeus.dal.core.AuthPrivateKeyEntity;
import com.ctrip.zeus.support.DaoFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.Key;
/**
* User: mag
* Date: 5/14/2015
* Time: 5:27 PM
*/
public class TokenManager {
private static final Logger logger = LoggerFactory.getLogger(TokenManager.class);
public static final String ALGORITHM = "DES";
private static String privateKey = "slbPrivateKey";
static {
try {
AuthPrivateKeyDao dao = new DaoFactory().getDao(AuthPrivateKeyDao.class);
AuthPrivateKeyDo privateKeyDo = dao.findFirst(AuthPrivateKeyEntity.READSET_FULL);
privateKey = privateKeyDo.getPrivateKey();
}catch (Exception e){
logger.error("error fetch private key from db.",e);
}
}
public static String generateToken() {
long currTime = System.currentTimeMillis();
byte[] timeBytes = toBytes(currTime);
try {
Key k = toKey(privateKey.getBytes("UTF-8"));
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, k);
return encryptBASE64(cipher.doFinal(timeBytes));
}catch (Exception e){
logger.error("error when generate token",e);
throw new RuntimeException(e);
}
}
public static boolean validateToken(String token) {
try {
Key key = toKey(privateKey.getBytes("UTF-8"));
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
long currTime = System.currentTimeMillis();
long decryptedTime = toLong(cipher.doFinal(decryptBASE64(token)));
if ((currTime - decryptedTime) < 60000){
return true;
}
} catch (Exception e) {
logger.error("validate token fail!",e);
}
return false;
}
private static byte[] decryptBASE64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
}
private static String encryptBASE64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
}
private static Key toKey(byte[] key) throws Exception {
DESKeySpec dks = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(dks);
return secretKey;
}
private static byte[] toBytes(long value){
byte[] result = new byte[8];
long tmp = value;
for (int i = 7; i >= 0; i--) {
result[i] = (byte) (tmp & (0xFFL));
tmp = tmp >> 8;
}
return result;
}
private static long toLong(byte[] value) {
long rt = 0;
for (int i = 0; i < 8; i++) {
int add = value[i] & (0xFF);
rt = rt << 8;
rt += add;
}
return rt;
}
public static void main(String[] args) throws Exception{
String token = TokenManager.generateToken();
System.out.println("token:" + token);
System.out.println("validate token:" + TokenManager.validateToken(token));
}
}

View file

@ -1,11 +1,16 @@
package com.ctrip.zeus.client; package com.ctrip.zeus.client;
import com.ctrip.zeus.auth.impl.IPAuthenticationFilter;
import com.ctrip.zeus.auth.impl.TokenManager;
import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.uri.UriComponent; import org.glassfish.jersey.uri.UriComponent;
import javax.ws.rs.client.Client; import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget; import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
/** /**
* @author:xingchaowang * @author:xingchaowang
@ -28,4 +33,10 @@ public abstract class AbstractRestClient {
protected WebTarget getTarget(){ protected WebTarget getTarget(){
return webTarget; return webTarget;
} }
protected MultivaluedMap<String, Object> getDefaultHeaders(){
MultivaluedMap<String, Object> map = new MultivaluedHashMap<>();
map.putSingle(IPAuthenticationFilter.SERVER_TOKEN_HEADER, TokenManager.generateToken());
return map;
}
} }

View file

@ -20,12 +20,12 @@ public class AppClient extends AbstractRestClient {
} }
public List<App> getAll() { public List<App> getAll() {
String res = getTarget().path("/api/app").request().get(String.class); String res = getTarget().path("/api/app").request().headers(getDefaultHeaders()).get(String.class);
return null; return null;
} }
public Response add(App app) { public Response add(App app) {
return getTarget().path("/api/app/add").request() return getTarget().path("/api/app/add").request().headers(getDefaultHeaders())
.post(Entity.entity( .post(Entity.entity(
String.format(App.JSON, app), String.format(App.JSON, app),
MediaType.APPLICATION_JSON MediaType.APPLICATION_JSON
@ -34,7 +34,7 @@ public class AppClient extends AbstractRestClient {
} }
public App get(String appName) { public App get(String appName) {
String res = getTarget().path("/api/app/get/" + appName).request(MediaType.APPLICATION_JSON).get(String.class); String res = getTarget().path("/api/app/get/" + appName).request(MediaType.APPLICATION_JSON).headers(getDefaultHeaders()).get(String.class);
try { try {
return DefaultJsonParser.parse(App.class, res); return DefaultJsonParser.parse(App.class, res);
} catch (IOException e) { } catch (IOException e) {

View file

@ -42,24 +42,24 @@ public class NginxClient extends AbstractRestClient {
public NginxResponse load() throws IOException{ public NginxResponse load() throws IOException{
String responseStr = getTarget().path("/api/nginx/load").request().get(String.class); String responseStr = getTarget().path("/api/nginx/load").request().headers(getDefaultHeaders()).get(String.class);
return DefaultJsonParser.parse(NginxResponse.class, responseStr); return DefaultJsonParser.parse(NginxResponse.class, responseStr);
} }
public NginxResponse write()throws IOException{ public NginxResponse write()throws IOException{
String responseStr = getTarget().path("/api/nginx/write").request().get(String.class); String responseStr = getTarget().path("/api/nginx/write").request().headers(getDefaultHeaders()).get(String.class);
return DefaultJsonParser.parse(NginxResponse.class, responseStr); return DefaultJsonParser.parse(NginxResponse.class, responseStr);
} }
public NginxResponse dyups(String upsName ,String upsCommands)throws IOException{ public NginxResponse dyups(String upsName ,String upsCommands)throws IOException{
String responseStr = getTarget().path("/api/nginx/dyups/"+upsName).request().post(Entity.entity(upsCommands, String responseStr = getTarget().path("/api/nginx/dyups/" + upsName).request().headers(getDefaultHeaders()).post(Entity.entity(upsCommands,
MediaType.APPLICATION_JSON MediaType.APPLICATION_JSON
),String.class); ),String.class);
return DefaultJsonParser.parse(NginxResponse.class,responseStr); return DefaultJsonParser.parse(NginxResponse.class,responseStr);
} }
public TrafficStatus getTrafficStatus() throws Exception { public TrafficStatus getTrafficStatus() throws Exception {
Response response = getTarget().path("").path("/api/nginx/trafficStatus").request().get(); Response response = getTarget().path("").path("/api/nginx/trafficStatus").request().headers(getDefaultHeaders()).get();
InputStream is = (InputStream)response.getEntity(); InputStream is = (InputStream)response.getEntity();
try { try {
return DefaultJsonParser.parse(TrafficStatus.class, IOUtils.inputStreamStringify(is)); return DefaultJsonParser.parse(TrafficStatus.class, IOUtils.inputStreamStringify(is));

View file

@ -20,12 +20,12 @@ public class SlbClient extends AbstractRestClient {
} }
public List<Slb> getAll() { public List<Slb> getAll() {
String res = getTarget().path("/api/slb").request().get(String.class); String res = getTarget().path("/api/slb").request().headers(getDefaultHeaders()).get(String.class);
return null; return null;
} }
public Response add(Slb slb) { public Response add(Slb slb) {
return getTarget().path("/api/slb/add").request() return getTarget().path("/api/slb/add").request().headers(getDefaultHeaders())
.post(Entity.entity( .post(Entity.entity(
String.format(Slb.JSON, slb), String.format(Slb.JSON, slb),
MediaType.APPLICATION_JSON MediaType.APPLICATION_JSON
@ -33,7 +33,7 @@ public class SlbClient extends AbstractRestClient {
} }
public Response update(Slb slb) { public Response update(Slb slb) {
return getTarget().path("/api/slb/update").request() return getTarget().path("/api/slb/update").request().headers(getDefaultHeaders())
.post(Entity.entity( .post(Entity.entity(
String.format(Slb.JSON, slb), String.format(Slb.JSON, slb),
MediaType.APPLICATION_JSON MediaType.APPLICATION_JSON
@ -41,7 +41,7 @@ public class SlbClient extends AbstractRestClient {
} }
public Slb get(String slbName) { public Slb get(String slbName) {
String res = getTarget().path("/api/slb/get/" + slbName).request(MediaType.APPLICATION_JSON).get(String.class); String res = getTarget().path("/api/slb/get/" + slbName).request(MediaType.APPLICATION_JSON).headers(getDefaultHeaders()).get(String.class);
try { try {
return DefaultJsonParser.parse(Slb.class, res); return DefaultJsonParser.parse(Slb.class, res);
} catch (IOException e) { } catch (IOException e) {

View file

@ -177,5 +177,17 @@
</query> </query>
</query-defs> </query-defs>
</entity> </entity>
<entity name="auth-private-key" table="auth_private_key" alias="apk" do-class="AuthPrivateKeyDo">
<query-defs>
<query name="find-first" type="SELECT">
<statement>
<![CDATA[
SELECT <FIELDS/>
FROM <TABLE/>
]]>
</statement>
</query>
</query-defs>
</entity>
</entities> </entities>

View file

@ -287,6 +287,42 @@
</query> </query>
</query-defs> </query-defs>
</entity> </entity>
<entity name="auth-private-key" table="auth_private_key" alias="apk">
<member name="private-key" field="private_key" value-type="String" length="50" nullable="false" key="true" />
<member name="data-change-last-time" field="DataChange_LastTime" value-type="Date" nullable="false" />
<var name="key-private-key" value-type="String" key-member="private-key" />
<primary-key name="PRIMARY" members="private_key" />
<index name="time idx" members="DataChange_LastTime ASC" />
<readsets>
<readset name="FULL" all="true" />
</readsets>
<updatesets>
<updateset name="FULL" all="true" />
</updatesets>
<query-defs>
<query name="find-by-PK" type="SELECT">
<param name="key-private-key" />
<statement><![CDATA[SELECT <FIELDS/>
FROM <TABLE/>
WHERE <FIELD name='private-key'/> = ${key-private-key}]]></statement>
</query>
<query name="insert" type="INSERT">
<statement><![CDATA[INSERT INTO <TABLE/>(<FIELDS/>)
VALUES(<VALUES/>)]]></statement>
</query>
<query name="update-by-PK" type="UPDATE">
<param name="key-private-key" />
<statement><![CDATA[UPDATE <TABLE/>
SET <FIELDS/>
WHERE <FIELD name='private-key'/> = ${key-private-key}]]></statement>
</query>
<query name="delete-by-PK" type="DELETE">
<param name="key-private-key" />
<statement><![CDATA[DELETE FROM <TABLE/>
WHERE <FIELD name='private-key'/> = ${key-private-key}]]></statement>
</query>
</query-defs>
</entity>
<entity name="auth-resource" table="auth_resource" alias="ar"> <entity name="auth-resource" table="auth_resource" alias="ar">
<member name="id" field="id" value-type="int" length="10" nullable="false" key="true" auto-increment="true" /> <member name="id" field="id" value-type="int" length="10" nullable="false" key="true" auto-increment="true" />
<member name="resource-name" field="resource_name" value-type="String" length="100" nullable="false" /> <member name="resource-name" field="resource_name" value-type="String" length="100" nullable="false" />
@ -296,6 +332,7 @@
<member name="data-change-last-time" field="DataChange_LastTime" value-type="Date" nullable="false" /> <member name="data-change-last-time" field="DataChange_LastTime" value-type="Date" nullable="false" />
<var name="key-id" value-type="int" key-member="id" /> <var name="key-id" value-type="int" key-member="id" />
<primary-key name="PRIMARY" members="id" /> <primary-key name="PRIMARY" members="id" />
<index name="time_idx" members="DataChange_LastTime ASC" />
<readsets> <readsets>
<readset name="FULL" all="true" /> <readset name="FULL" all="true" />
</readsets> </readsets>
@ -336,6 +373,7 @@
<primary-key name="PRIMARY" members="id" /> <primary-key name="PRIMARY" members="id" />
<index name="role_idx" members="role_name ASC" /> <index name="role_idx" members="role_name ASC" />
<index name="res_idx" members="resource_name ASC" /> <index name="res_idx" members="resource_name ASC" />
<index name="time_idx" members="DataChange_LastTime ASC" />
<readsets> <readsets>
<readset name="FULL" all="true" /> <readset name="FULL" all="true" />
</readsets> </readsets>
@ -375,6 +413,7 @@
<var name="key-id" value-type="int" key-member="id" /> <var name="key-id" value-type="int" key-member="id" />
<primary-key name="PRIMARY" members="id" /> <primary-key name="PRIMARY" members="id" />
<index name="role_idx" unique="true" members="role_name ASC" /> <index name="role_idx" unique="true" members="role_name ASC" />
<index name="time_idx" members="DataChange_LastTime ASC" />
<readsets> <readsets>
<readset name="FULL" all="true" /> <readset name="FULL" all="true" />
</readsets> </readsets>
@ -407,13 +446,14 @@
</entity> </entity>
<entity name="auth-user" table="auth_user" alias="au"> <entity name="auth-user" table="auth_user" alias="au">
<member name="id" field="id" value-type="int" length="10" nullable="false" key="true" auto-increment="true" /> <member name="id" field="id" value-type="int" length="10" nullable="false" key="true" auto-increment="true" />
<member name="user-name" field="user_name" value-type="String" length="50" nullable="false" /> <member name="user-name" field="user_name" value-type="String" length="50" />
<member name="description" field="description" value-type="String" length="100" /> <member name="description" field="description" value-type="String" length="100" />
<member name="created-time" field="created_time" value-type="Date" /> <member name="created-time" field="created_time" value-type="Date" />
<member name="data-change-last-time" field="DataChange_LastTime" value-type="Date" nullable="false" /> <member name="data-change-last-time" field="DataChange_LastTime" value-type="Date" nullable="false" />
<var name="key-id" value-type="int" key-member="id" /> <var name="key-id" value-type="int" key-member="id" />
<primary-key name="PRIMARY" members="id" /> <primary-key name="PRIMARY" members="id" />
<index name="usr_name_idx" unique="true" members="user_name ASC" /> <index name="usr_name_idx" unique="true" members="user_name ASC" />
<index name="time_idx" members="DataChange_LastTime ASC" />
<readsets> <readsets>
<readset name="FULL" all="true" /> <readset name="FULL" all="true" />
</readsets> </readsets>
@ -446,15 +486,15 @@
</entity> </entity>
<entity name="auth-user-role" table="auth_user_role" alias="aur"> <entity name="auth-user-role" table="auth_user_role" alias="aur">
<member name="id" field="id" value-type="int" length="10" nullable="false" key="true" auto-increment="true" /> <member name="id" field="id" value-type="int" length="10" nullable="false" key="true" auto-increment="true" />
<member name="user-name" field="user_name" value-type="String" length="50" nullable="false" /> <member name="user-name" field="user_name" value-type="String" length="50" />
<member name="role-name" field="role_name" value-type="String" length="50" nullable="false" /> <member name="role-name" field="role_name" value-type="String" length="50" />
<member name="group" field="group" value-type="String" length="50" nullable="false" /> <member name="group" field="group" value-type="String" length="50" />
<member name="created-time" field="created_time" value-type="Date" /> <member name="created-time" field="created_time" value-type="Date" />
<member name="data-change-last-time" field="DataChange_LastTime" value-type="Date" nullable="false" /> <member name="data-change-last-time" field="DataChange_LastTime" value-type="Date" nullable="false" />
<var name="key-id" value-type="int" key-member="id" /> <var name="key-id" value-type="int" key-member="id" />
<primary-key name="PRIMARY" members="id" /> <primary-key name="PRIMARY" members="id" />
<index name="usr_role_idx" unique="true" members="user_name ASC" />
<index name="usr_idx" members="user_name ASC" /> <index name="usr_idx" members="user_name ASC" />
<index name="time_idx" members="DataChange_LastTime ASC" />
<readsets> <readsets>
<readset name="FULL" all="true" /> <readset name="FULL" all="true" />
</readsets> </readsets>
@ -566,7 +606,7 @@
</query-defs> </query-defs>
</entity> </entity>
<entity name="conf-app-slb-active" table="conf_app_slb_active" alias="casa"> <entity name="conf-app-slb-active" table="conf_app_slb_active" alias="casa">
<member name="id" field="id" value-type="long" length="19" nullable="false" key="true" /> <member name="id" field="id" value-type="long" length="19" nullable="false" key="true" auto-increment="true" />
<member name="app-name" field="app_name" value-type="String" length="200" nullable="false" /> <member name="app-name" field="app_name" value-type="String" length="200" nullable="false" />
<member name="slb-name" field="slb_name" value-type="String" length="200" nullable="false" /> <member name="slb-name" field="slb_name" value-type="String" length="200" nullable="false" />
<member name="slb-virtual-server-name" field="slb_virtual_server_name" value-type="String" length="200" nullable="false" /> <member name="slb-virtual-server-name" field="slb_virtual_server_name" value-type="String" length="200" nullable="false" />
@ -646,9 +686,11 @@
</entity> </entity>
<entity name="dist-lock" table="dist_lock" alias="dl"> <entity name="dist-lock" table="dist_lock" alias="dl">
<member name="lock-key" field="lock_key" value-type="String" length="255" nullable="false" key="true" /> <member name="lock-key" field="lock_key" value-type="String" length="255" nullable="false" key="true" />
<member name="created-time" field="created_time" value-type="long" length="19" nullable="false" /> <member name="created-time" field="created_time" value-type="long" length="19" />
<member name="data-change-last-time" field="DataChange_LastTime" value-type="Date" nullable="false" />
<var name="key-lock-key" value-type="String" key-member="lock-key" /> <var name="key-lock-key" value-type="String" key-member="lock-key" />
<primary-key name="PRIMARY" members="lock_key" /> <primary-key name="PRIMARY" members="lock_key" />
<index name="dcl_key" members="DataChange_LastTime ASC" />
<readsets> <readsets>
<readset name="FULL" all="true" /> <readset name="FULL" all="true" />
</readsets> </readsets>

View file

@ -71,6 +71,15 @@
<data-source-name>zeus</data-source-name> <data-source-name>zeus</data-source-name>
</configuration> </configuration>
</component> </component>
<component>
<role>org.unidal.dal.jdbc.mapping.TableProvider</role>
<role-hint>auth-private-key</role-hint>
<implementation>org.unidal.dal.jdbc.mapping.SimpleTableProvider</implementation>
<configuration>
<physical-table-name>auth_private_key</physical-table-name>
<data-source-name>zeus</data-source-name>
</configuration>
</component>
<component> <component>
<role>org.unidal.dal.jdbc.mapping.TableProvider</role> <role>org.unidal.dal.jdbc.mapping.TableProvider</role>
<role-hint>auth-resource</role-hint> <role-hint>auth-resource</role-hint>
@ -332,6 +341,15 @@
</requirement> </requirement>
</requirements> </requirements>
</component> </component>
<component>
<role>com.ctrip.zeus.dal.core.AuthPrivateKeyDao</role>
<implementation>com.ctrip.zeus.dal.core.AuthPrivateKeyDao</implementation>
<requirements>
<requirement>
<role>org.unidal.dal.jdbc.QueryEngine</role>
</requirement>
</requirements>
</component>
<component> <component>
<role>com.ctrip.zeus.dal.core.AuthResourceDao</role> <role>com.ctrip.zeus.dal.core.AuthResourceDao</role>
<implementation>com.ctrip.zeus.dal.core.AuthResourceDao</implementation> <implementation>com.ctrip.zeus.dal.core.AuthResourceDao</implementation>

View file

@ -38,6 +38,7 @@
<table name="auth_resource_role"/> <table name="auth_resource_role"/>
<table name="auth_user_role"/> <table name="auth_user_role"/>
<table name="auth_user"/> <table name="auth_user"/>
<table name="auth_private_key"/>
</group> </group>
</jdbc> </jdbc>
</wizard> </wizard>