Sunday, July 28, 2013

Upload java script files to Amazon S3 using Ruby

require "s3"
service = S3::Service.new(:access_key_id => "KEY.................",
                          :secret_access_key => "SECRET ACCESS KEY....................")

bucket = service.buckets.find("s3 bucket name")

new_object = bucket.objects.build("s3 object location")
new_object.content = open(s3 object name)
new_object.content_type = "application/x-javascript"
new_object.cache_control = "max-age=604800"
new_object.content_encoding = "gzip"
new_object.save

Store OAuth 10a token in the database

1. Create a token table as below
 This is how you do in mysql
CREATE TABLE `token` (
 `id` int(10) NOT NULL AUTO_INCREMENT,
 `consumer_id` int(10) NOT NULL,
 `public_key` varchar(255) DEFAULT NULL,
 `private_key` varchar(255) DEFAULT NULL,
 `created_date` timestamp NULL DEFAULT NULL,
 `callback_url` varchar(255) DEFAULT NULL,
 `verifier` varchar(255) DEFAULT NULL,
 `access_token` int(2) DEFAULT NULL,
 `authentication` blob,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

2. Write a custom JDBC token service class
public class CustomTokenService {
private TokenDao tokenDao;

public CustomTokenService(TokenDao tokenDao) {
this.tokenDao = tokenDao;
}

public OAuthProviderTokenImpl readToken(String token) {
List<Token> sessionList = tokenDao.getNamedQueryAndNamedParam("Token.findById", "id", token);
Token session = sessionList.get(0);
for (Token t : sessionList) {
if (t.getIsActive() == 1) {
session = t;
}
}
session.setLastAccessedDate(new Date());
tokenDao.saveOrUpdate(session);
OAuthProviderTokenImpl accessToken = createOAuthProviderToken(session);
return accessToken;
}

public void storeToken(String tokenValue, OAuthProviderTokenImpl token) {         // Token class is orm of token table
Token customToken = new Token();
customToken.setCreatedDate(new Date());

Authentication userAuthentication = token.getUserAuthentication();
if (userAuthentication != null) {
byte[] authSerialized = serializeAuthentication(userAuthentication);
customToken.setUserAuthentication(authSerialized);
}

String consumerKey = token.getConsumerKey();
// need to create a consumer object
customToken.setConsumerId(consumer);
customToken.setSessionId(token.getValue());
String callbackUrl = token.getCallbackUrl();
String verifier = token.getVerifier();
customToken.setCallbackUrl(callbackUrl);
customToken.setVerifier(verifier);
customToken.setPrivateKey(token.getSecret());
customToken.setPublicKey(token.getValue());

Integer accessToken = token.isAccessToken() ? 1 : 0;
customToken.setAccessToken(accessToken);
tokenDao.saveOrUpdate(customToken);
}

public OAuthProviderTokenImpl removeToken(String tokenValue) {
// remove or null from the database and return the object
tokenDao.saveOrUpdate(token);
OAuthProviderTokenImpl tokenImpl = createOAuthProviderToken(token);
return tokenImpl;
}

private OAuthProviderTokenImpl createOAuthProviderToken(Token findById) {
OAuthProviderTokenImpl token = new OAuthProviderTokenImpl();
if (findById.getUserAuthentication() != null) {
Authentication userAuthentication = deserializeAuthentication(findById
.getUserAuthentication());
token.setUserAuthentication(userAuthentication);
}
//create the consumer key
token.setConsumerKey(consumerKey);
boolean accessToken = false;
if (findById.getAccessToken() == 1) {
accessToken = true;
}
token.setAccessToken(accessToken);
token.setSecret(findById.getPrivateKey());
token.setValue(findById.getPublicKey());
token.setCallbackUrl(findById.getCallbackUrl());
token.setVerifier(findById.getVerifier());
return token;
}

protected String extractTokenKey(String value) {
if (value == null) {
return null;
}
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(
"MD5 algorithm not available.  Fatal (should be in the JDK).");
}

try {
byte[] bytes = digest.digest(value.getBytes("UTF-8"));
return String.format("%032x", new BigInteger(1, bytes));
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(
"UTF-8 encoding not available.  Fatal (should be in the JDK).");
}
}

protected byte[] serializeAuthentication(Authentication authentication) {
return SerializationUtils.serialize(authentication);
}

protected Authentication deserializeAuthentication(byte[] authentication) {
return (Authentication) SerializationUtils.deserialize(authentication);
}
}

3. Write Custom OAuth Token Service
public class CustomOAuthTokenService extends RandomValueProviderTokenServices{

CustomTokenService customTokenService;
protected final ConcurrentHashMap<String, OAuthProviderTokenImpl> tokenStore = new ConcurrentHashMap<String, OAuthProviderTokenImpl>();

public CustomOAuthTokenService(CustomTokenService customTokenService) {
super();
this.customTokenService = customTokenService;
}

@Override
protected OAuthProviderTokenImpl readToken(String token) {
OAuthProviderTokenImpl readToken = customTokenService.readToken(token);
return readToken;
}

@Override
protected void storeToken(String tokenValue, OAuthProviderTokenImpl token) {
customTokenService.storeToken(tokenValue, token);
}

@Override
protected OAuthProviderTokenImpl removeToken(String tokenValue) {
return customTokenService.removeToken(tokenValue);
}

}

4. Changes to Spring security config file

<beans:bean id="tokenServices" class="....CustomOAuthTokenService">
<beans:constructor-arg ref="customTokenService" />
</beans:bean>

<beans:bean id="customTokenService" class=".....CustomTokenService">
<beans:constructor-arg>
<beans:ref bean="tokenDao" />
</beans:constructor-arg>
</beans:bean>

Permission based authorization with OAuth 10a

OAuth 10a deals with roal based authorization. 
Can we do the permission based authorization with oauth 10a ?

That is can we authorize a URL pattern, can we authorize frequency of request URL 
Or can we authorize particulate client IP to access the resource

The easiest way is to write a custom expression voter as below

public class CExpressionVoter implements AccessDecisionVoter<FilterInvocation> {
    public int vote(Authentication authentication, FilterInvocation fi, Collection<ConfigAttribute> attributes) {
        assert authentication != null;
        assert fi != null;
        assert attributes != null;

        if(authentication.getPrincipal()!=null ) {
        Object principal = authentication.getPrincipal();
        if(principal instanceof UserDetails) {
        UserDetails userDetails = (UserDetails)principal;
        if(userDetails.getUsername().equalsIgnoreCase("anonymousUser")){
        return -1;
        } else {
        Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
          int i = -1;
        for (GrantedAuthority grantedAuthority : authorities) {
String uriAuthorityPattern = grantedAuthority.getAuthority().toLowerCase();
String uriRequest = fi.getRequestUrl().toLowerCase();
String fullRequestUrl = fi.getFullRequestUrl();

String delimiters = "/\\s*|\\?\\s*";
String[] uriPatternArray = uriRequest.split(delimiters);
String uriPattern = null;
if(uriPatternArray !=null & uriPatternArray.length >=2) {
uriPattern = uriPatternArray[1];
}
// This is the sample to check the URL pattern. Likewise you can do other authentications, All the autorities can be loaded to
// user detail object using a custom user detail service, sample given below
if (uriPattern!=null & uriPattern.equalsIgnoreCase(uriAuthorityPattern)){
i = 1; break;
} else {
i = -1;
}
}
        return i;        
        }
       
        if (principal instanceof String) {
        if(((String) principal).equalsIgnoreCase("anonymousUser")){
        return -1;
        }
        }
        }
        return 1;
    }
    public boolean supports(ConfigAttribute attribute) {
    return true;
    }

    public boolean supports(Class<?> clazz) {
        return clazz.isAssignableFrom(FilterInvocation.class);
    }
}

Custom User Detail Service
public class CUserDetailService implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
ArrayList<String> authority  = new ArrayList<String>();
// Get the values from the database and add as arrayList
UserDetails result = new CustomUserDetails(findById, authority);
return result;
}

}

Custom User Details

public class CustomUserDetails implements UserDetails {
private String userName;
private String password;
private Collection<GrantedAuthority> grantedAuthorities;

public CustomUserDetails(CustomUser user, List<String> authority){
this.grantedAuthorities = new ArrayList<GrantedAuthority>();
for (String p : authority) {
GrantedAuthority ga = new SimpleGrantedAuthority(p);
this.grantedAuthorities.add(ga);
}
}

public Collection<? extends GrantedAuthority> getAuthorities() {
return this.grantedAuthorities;
}

// write inherited methods for UserDetails
}

Custom Secure Resource Filter
// this is a dummy implementation
public class CSecureResourceFilter implements FilterInvocationSecurityMetadataSource {
public Collection<ConfigAttribute> getAllConfigAttributes() {
StringBuilder rolesStringBuilder = new StringBuilder();
rolesStringBuilder.append("USER1");
List<ConfigAttribute> createListFromCommaDelimitedString = SecurityConfig.createListFromCommaDelimitedString(rolesStringBuilder.toString());
return createListFromCommaDelimitedString;
}

public Collection<ConfigAttribute> getAttributes(Object filter) throws IllegalArgumentException {
StringBuilder rolesStringBuilder = new StringBuilder();
rolesStringBuilder.append("USER1");
return SecurityConfig.createListFromCommaDelimitedString(rolesStringBuilder.toString());
}
public boolean supports(Class<?> arg0) {
return true;
}
}


Spring security configuration file

..

<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<beans:constructor-arg name="decisionVoters">
<beans:list>
<beans:bean class="..................CExpressionVoter" />
</beans:list>
</beans:constructor-arg> 
</beans:bean>

<http use-expressions="true" auto-config='true' access-denied-page="/login.jsp" > 
<form-login authentication-failure-url="/login.jsp" default-target-url="/index.jsp" login-page="/login.jsp" login-processing-url="/login.do" />
<custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="filterSecurityInterceptor" /> 
</http> 

<beans:bean id="customUserDetailService" class=".....CUserDetailService" /> 

<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="customUserDetailService"/> 
</authentication-manager>

<beans:bean id="customSecureResourceFilter" class=".......CSecureResourceFilter"/>


<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="authenticationManager"/>
<beans:property name="accessDecisionManager" ref="accessDecisionManager"/>
<beans:property name="securityMetadataSource" ref="customSecureResourceFilter"/>

</beans:bean>