org.apache.usergrid.security.ApigeeSSO2ProviderIT.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.usergrid.security.ApigeeSSO2ProviderIT.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.usergrid.security;

import io.jsonwebtoken.*;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.impl.crypto.RsaProvider;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.usergrid.NewOrgAppAdminRule;
import org.apache.usergrid.ServiceITSetup;
import org.apache.usergrid.ServiceITSetupImpl;
import org.apache.usergrid.cassandra.ClearShiroSubject;
import org.apache.usergrid.management.ManagementService;
import org.apache.usergrid.management.UserInfo;
import org.apache.usergrid.persistence.Entity;
import org.apache.usergrid.persistence.EntityManager;
import org.apache.usergrid.persistence.SimpleEntityRef;
import org.apache.usergrid.persistence.entities.User;
import org.apache.usergrid.security.sso.ApigeeSSO2Provider;
import org.apache.usergrid.security.tokens.TokenInfo;
import org.apache.usergrid.security.tokens.exceptions.BadTokenException;
import org.junit.*;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

import static org.apache.commons.codec.binary.Base64.decodeBase64;

/**
 * Created by Dave Johnson (snoopdave@apache.org) on 10/25/16.
 */
public class ApigeeSSO2ProviderIT {
    private static final Logger logger = LoggerFactory.getLogger(ApigeeSSO2ProviderIT.class);

    @ClassRule
    public static final ServiceITSetup setup = new ServiceITSetupImpl();

    @Test
    public void testBasicOperation() throws Exception {

        // create keypair
        KeyPair kp = RsaProvider.generateKeyPair(1024);
        PublicKey publicKey = kp.getPublic();
        PrivateKey privateKey = kp.getPrivate();

        // create provider with private key
        ApigeeSSO2Provider provider = new MockApigeeSSO2Provider();
        provider.setManagement(setup.getMgmtSvc());
        provider.setPublicKey(publicKey);

        // create user, claims and a token for those things
        User user = createUser();
        long exp = System.currentTimeMillis() + 10000;
        Map<String, Object> claims = createClaims(user.getUsername(), user.getEmail(), exp);
        String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.RS256, privateKey).compact();

        // test that provider can validate the token, get user, return token info
        TokenInfo tokenInfo = provider.validateAndReturnTokenInfo(token, 86400L);
        Assert.assertNotNull(tokenInfo);
    }

    @Test
    public void testExpiredToken() throws Exception {

        // create keypair
        KeyPair kp = RsaProvider.generateKeyPair(1024);
        PublicKey publicKey = kp.getPublic();
        PrivateKey privateKey = kp.getPrivate();

        // create provider with private key
        ApigeeSSO2Provider provider = new MockApigeeSSO2Provider();
        provider.setManagement(setup.getMgmtSvc());
        provider.setPublicKey(publicKey);

        // create user, claims and a token for those things
        User user = createUser();
        long exp = System.currentTimeMillis() - 1500;
        Map<String, Object> claims = createClaims(user.getUsername(), user.getEmail(), exp);
        String token = Jwts.builder().setClaims(claims).setExpiration(new Date())
                .signWith(SignatureAlgorithm.RS256, privateKey).compact();

        Thread.sleep(500); // wait for claims to timeout

        // test that token is expired
        try {
            provider.validateAndReturnTokenInfo(token, 86400L);
            Assert.fail("Should have failed due to expired token");

        } catch (BadTokenException e) {
            Assert.assertTrue(e.getCause() instanceof ExpiredJwtException);
        }
    }

    @Test
    public void testMalformedToken() throws Exception {

        // create keypair
        KeyPair kp = RsaProvider.generateKeyPair(1024);
        PublicKey publicKey = kp.getPublic();

        // create provider with private key
        ApigeeSSO2Provider provider = new MockApigeeSSO2Provider();
        provider.setManagement(setup.getMgmtSvc());
        provider.setPublicKey(publicKey);

        // test that token is malformed
        try {
            provider.getClaims("{;aklsjd;fkajsd;fkjasd;lfkj}");
            Assert.fail("Should have failed due to malformed token");

        } catch (BadTokenException e) {
            Assert.assertTrue(e.getCause() instanceof MalformedJwtException);
        }
    }

    @Test
    public void testNewPublicKeyFetch() throws Exception {

        // create old keypair
        KeyPair kp = RsaProvider.generateKeyPair(1024);
        PublicKey publicKey = kp.getPublic();
        PrivateKey privateKey = kp.getPrivate();

        // create new keypair
        KeyPair kpNew = RsaProvider.generateKeyPair(1024);
        PublicKey publicKeyNew = kpNew.getPublic();
        PrivateKey privateKeyNew = kpNew.getPrivate();

        // create mock provider with old and old key
        MockApigeeSSO2ProviderNewKey provider = new MockApigeeSSO2ProviderNewKey(publicKey, publicKeyNew);
        provider.setManagement(setup.getMgmtSvc());

        // create user, claims and a token for those things. Sign with new public key
        User user = createUser();
        long exp = System.currentTimeMillis() + 10000;
        Map<String, Object> claims = createClaims(user.getUsername(), user.getEmail(), exp);
        String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.RS256, privateKeyNew).compact();

        // test that provider can validate the token, get user, return token info
        TokenInfo tokenInfo = provider.validateAndReturnTokenInfo(token, 86400L);
        Assert.assertNotNull(tokenInfo);

        // assert that provider called for new key
        Assert.assertTrue(provider.isGetPublicKeyCalled());

        // try it again, but this time it should fail due to freshness value

        provider.setPublicKey(publicKey); // set old key

        // test that signature exception thrown
        try {
            provider.validateAndReturnTokenInfo(token, 86400L);
            Assert.fail("Should have failed due to bad signature");

        } catch (BadTokenException e) {
            Assert.assertTrue(e.getCause() instanceof SignatureException);
        }

    }

    @Test
    public void testBadSignature() throws Exception {

        // create old keypair
        KeyPair kp = RsaProvider.generateKeyPair(1024);
        PublicKey publicKey = kp.getPublic();
        PrivateKey privateKey = kp.getPrivate();

        // create new keypair
        KeyPair kpNew = RsaProvider.generateKeyPair(1024);
        PrivateKey privateKeyNew = kpNew.getPrivate();

        // create mock provider with old public key
        ApigeeSSO2Provider provider = new MockApigeeSSO2ProviderNewKey(publicKey, publicKey);
        provider.setManagement(setup.getMgmtSvc());

        // create user, claims and a token for those things. Sign with new public key
        User user = createUser();
        long exp = System.currentTimeMillis() + 10000;
        Map<String, Object> claims = createClaims(user.getUsername(), user.getEmail(), exp);
        String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.RS256, privateKeyNew).compact();

        // test that signature exception thrown
        try {
            provider.validateAndReturnTokenInfo(token, 86400L);
            Assert.fail("Should have failed due to bad signature");

        } catch (BadTokenException e) {
            Assert.assertTrue(e.getCause() instanceof SignatureException);
        }

    }

    private User createUser() throws Exception {
        String rando = RandomStringUtils.randomAlphanumeric(10);
        String username = "user_" + rando;
        String email = username + "@example.com";
        Map<String, Object> properties = new HashMap<String, Object>() {
            {
                put("username", username);
                put("email", email);
            }
        };
        EntityManager em = setup.getEmf().getEntityManager(setup.getEmf().getManagementAppId());
        Entity entity = em.create("user", properties);

        return em.get(new SimpleEntityRef(User.ENTITY_TYPE, entity.getUuid()), User.class);
    }

    private Map<String, Object> createClaims(final String username, final String email, long exp) {
        return new HashedMap<String, Object>() {
            {
                put("jti", "c7df0339-3847-450b-a925-628ef237953a");
                put("sub", "b6d62259-217b-4e96-8f49-e00c366e4fed");
                put("scope", "size = 5");
                put("client_id", "dummy1");
                put("azp", "dummy2");
                put("grant_type", "password");
                put("user_id", "b6d62259-217b-4e96-8f49-e00c366e4fed");
                put("origin", "usergrid");
                put("user_name", username);
                put("email", email);
                put("rev_sig", "dfe5d0d3");
                put("exp", exp);
                put("iat", System.currentTimeMillis());
                put("iss", "https://jwt.example.com/token");
                put("zid", "uaa");
                put("aud", " size = 6");
            }
        };
    }
}

class MockApigeeSSO2Provider extends ApigeeSSO2Provider {
    private static final Logger logger = LoggerFactory.getLogger(MockApigeeSSO2Provider.class);

    @Override
    public PublicKey getPublicKey(String keyUrl) {
        return publicKey;
    }

    @Override
    public void setPublicKey(PublicKey publicKey) {
        this.publicKey = publicKey;
    }
}

class MockApigeeSSO2ProviderNewKey extends ApigeeSSO2Provider {
    private static final Logger logger = LoggerFactory.getLogger(MockApigeeSSO2Provider.class);

    private PublicKey newKey;
    private boolean getPublicKeyCalled = false;

    public MockApigeeSSO2ProviderNewKey(PublicKey oldKey, PublicKey newKey) {
        this.publicKey = oldKey;
        this.newKey = newKey;
        this.properties = new Properties();
    }

    @Override
    public PublicKey getPublicKey(String keyUrl) {
        getPublicKeyCalled = true;
        return newKey;
    }

    public boolean isGetPublicKeyCalled() {
        return getPublicKeyCalled;
    }
}