Skip to content

Commit

Permalink
mfa screen styling, mockmvc test refactor
Browse files Browse the repository at this point in the history
[#151568420] https://www.pivotaltracker.com/story/show/151568420
Signed-off-by: Henry Zhao <henryzh16@gmail.com>
  • Loading branch information
medvedzver authored and 6palace committed Oct 26, 2017
1 parent 45d8a0e commit ff2384c
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 144 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
import com.warrenstrange.googleauth.GoogleAuthenticatorException;
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator;
import com.warrenstrange.googleauth.ICredentialRepository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
import org.cloudfoundry.identity.uaa.mfa_provider.MfaProvider;
import org.cloudfoundry.identity.uaa.mfa_provider.MfaProviderProvisioning;
import org.cloudfoundry.identity.uaa.mfa_provider.UserGoogleMfaCredentialsProvisioning;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
Expand All @@ -29,6 +33,7 @@ public class TotpEndpoint {
private GoogleAuthenticatorConfig config = new GoogleAuthenticatorConfig.GoogleAuthenticatorConfigBuilder().build();
private GoogleAuthenticator authenticator = new GoogleAuthenticator(config);
private UserGoogleMfaCredentialsProvisioning userGoogleMfaCredentialsProvisioning;
private MfaProviderProvisioning mfaProviderProvisioning;
private Log logger = LogFactory.getLog(TotpEndpoint.class);
public static final String MFA_VALIDATE_USER = "MFA_VALIDATE_USER";

Expand All @@ -50,14 +55,17 @@ public String generateQrUrl(HttpSession session, Model model) throws NoSuchAlgor
return "redirect:/login/mfa/verify";
} else{
//TODO set credential to inactive
String url = GoogleAuthenticatorQRGenerator.getOtpAuthURL("UAA", uaaPrincipal.getName(), createCredentials(uaaPrincipal.getId()));
String url = GoogleAuthenticatorQRGenerator.getOtpAuthURL("UAA", uaaPrincipal.getName(), createCredentials(uaaPrincipal.getId())); //No op save on repo
MfaProvider provider = mfaProviderProvisioning.retrieve(IdentityZoneHolder.get().getConfig().getMfaConfig().getProviderId(), IdentityZoneHolder.get().getId());
model.addAttribute("qrurl", url);
model.addAttribute("mfa_provider", provider.getName());
session.setAttribute("QR_CODE_CREDS","creds");
return "qr_code";
}
}

@RequestMapping(value = {"/login/mfa/verify"}, method = RequestMethod.GET)
public String totpAuthorize(HttpSession session, Model mock) {
public String totpAuthorize(HttpSession session) {
UaaPrincipal uaaPrincipal = getSessionAuthPrincipal(session);
if(uaaPrincipal == null) return "redirect:/login";

Expand All @@ -77,7 +85,6 @@ public String validateCode(Model model,
HttpSession session,
@RequestParam("code") String code)
throws NoSuchAlgorithmException, IOException {
int codeValue;
UaaAuthentication sessionAuth = session.getAttribute(MFA_VALIDATE_USER) instanceof UaaAuthentication ? (UaaAuthentication) session.getAttribute(MFA_VALIDATE_USER) : null;
UaaPrincipal uaaPrincipal;
if(sessionAuth != null) {
Expand All @@ -87,8 +94,9 @@ public String validateCode(Model model,
}

try {
codeValue = Integer.valueOf(code);
Integer codeValue = Integer.valueOf(code);
if(authenticator.authorizeUser(uaaPrincipal.getId(), codeValue)) {
//TODO must not be called every time user enters the code. This is a one time action.
userGoogleMfaCredentialsProvisioning.activateUser(uaaPrincipal.getId());

session.removeAttribute(MFA_VALIDATE_USER);
Expand Down Expand Up @@ -121,4 +129,7 @@ private UaaPrincipal getSessionAuthPrincipal(HttpSession session) {
}


public void setMfaProviderProvisioning(MfaProviderProvisioning mfaProviderProvisioning) {
this.mfaProviderProvisioning = mfaProviderProvisioning;
}
}
1 change: 1 addition & 0 deletions server/src/main/resources/spring/login-ui.xml
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,7 @@

<bean id="totpEndpoint" class="org.cloudfoundry.identity.uaa.login.TotpEndpoint">
<property name="userGoogleMfaCredentialsProvisioning" ref="userGoogleMfaCredentialsProvisioning"/>
<property name="mfaProviderProvisioning" ref="mfaProviderProvisioning" />
</bean>

</beans>
7 changes: 6 additions & 1 deletion server/src/main/resources/templates/web/enter_code.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,17 @@ <h1>Google Authenticator Code</h1>
Enter the 6-digit code displayed in Google Authenticator app:
</p>
<form th:action="@{/login/mfa/verify.do}" method="post" novalidate="novalidate">
<div th:if="${error}" th:text="${error}" class="error-message"></div>
<div class="page">
<input name="code" type="number" placeholder="Code" autofocus="autofocus" class="form-control mrs txt-c em-high" maxlength="6"/>
<button type="submit" class="btn btn-highlight mlxl">Verify</button>
</div>
<div th:if="${error}" th:text="${error}" class="error-color mtl"></div>
</form>
<a href="/login/mfa/register" th:href="@{/login/mfa/register}">
<button id="Back"
type="Button"
class="btn btn-default mtl">Back</button>
</a>
</div>
</div>
</body>
Expand Down
20 changes: 9 additions & 11 deletions server/src/main/resources/templates/web/qr_code.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,18 @@
layout:decorator="layouts/pivotal-ui-main">
<body>
<div class="island" layout:fragment="page-content">
<h1>MFA</h1>
<h1 id="mfa-provider" th:text="${mfa_provider}"/>
<div class="panel-body">
<h2 class="mtxl">Setup Multifactor Authentication with Google Authenticator</h2>
<p class="mtxl">You will be asked for a passcode when you sign in for security.
<div class="paxl">
<ol>
<li>Install Google Authenticator on your mobile device from the <a href="https://itunes.apple.com/us/app/google-authenticator/id388497605">App Store on your iPhone</a> or <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Play on your Android. </a></li>
<li>Open Google Authenticator on your mobile device.</li>
<li>Tap the "+" button.</li>
<li>Tap "Scan barcode".</li>
<li>Scan this barcode:</li>
</ol>
</div>
<img id="qr" th:src="${qrurl}" class="center-block"/>
<ol style="padding-left:1em;">
<li>Install Google Authenticator on your mobile device from the <a href="https://itunes.apple.com/us/app/google-authenticator/id388497605">App Store on your iPhone</a> or <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Play on your Android. </a></li>
<li>Open Google Authenticator on your mobile device.</li>
<li>Tap the "+" button.</li>
<li>Tap "Scan barcode".</li>
<li>Scan this barcode:</li>
</ol>
<img id="qr" th:src="${qrurl}" alt="error getting qr code" class="center-block"/>
<p class="mtl">Once you have registered with Google Authenticator, click Next. </p>
<div class="center-block">
<a href="/login" th:href="@{/login}">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public void testGenerateQrUrlForNewUserRegistration() throws Exception{
public void testTotpAuthorizePageNoAuthentication() throws Exception{
when(uaaAuthentication.getPrincipal()).thenReturn(null);

String returnView = endpoint.totpAuthorize(session, mock(Model.class));
String returnView = endpoint.totpAuthorize(session);

assertEquals("redirect:/login", returnView);
}
Expand All @@ -86,7 +86,7 @@ public void testTotpAuthorizePageNoAuthentication() throws Exception{
public void testTotpAuthorizePage() throws Exception{
when(uaaAuthentication.getPrincipal()).thenReturn(new UaaPrincipal(userId, "Marissa", null, null, null, null), null, null);

String returnView = endpoint.totpAuthorize(session, mock(Model.class));
String returnView = endpoint.totpAuthorize(session);
assertEquals("enter_code", returnView);
}

Expand Down
2 changes: 1 addition & 1 deletion uaa/src/main/webapp/WEB-INF/spring-servlet.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
</bean>

<bean id="mfaConfigValidator" class="org.cloudfoundry.identity.uaa.zone.MfaConfigValidator">
<property name="mfaProviderProvisioning" ref="mfaProvideProvisioning"/>
<property name="mfaProviderProvisioning" ref="mfaProviderProvisioning"/>
</bean>

<bean id="sessionCookieConfig" class="org.cloudfoundry.identity.uaa.web.UaaSessionCookieConfig">
Expand Down
4 changes: 2 additions & 2 deletions uaa/src/main/webapp/WEB-INF/spring/multitenant-endpoints.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
<constructor-arg ref="metaDataProviders"/>
</bean>

<bean id="mfaProvideProvisioning" class="org.cloudfoundry.identity.uaa.mfa_provider.JdbcMfaProviderProvisioning">
<bean id="mfaProviderProvisioning" class="org.cloudfoundry.identity.uaa.mfa_provider.JdbcMfaProviderProvisioning">
<constructor-arg type="org.springframework.jdbc.core.JdbcTemplate" ref="jdbcTemplate"/>
<constructor-arg type="org.cloudfoundry.identity.uaa.mfa_provider.MfaProviderValidator" ref="mfaProviderValidator"/>
</bean>
Expand All @@ -96,7 +96,7 @@
</bean>

<bean id="mfaProviderEndpoints" class="org.cloudfoundry.identity.uaa.mfa_provider.MfaProviderEndpoints">
<property name="mfaProviderProvisioning" ref="mfaProvideProvisioning"/>
<property name="mfaProviderProvisioning" ref="mfaProviderProvisioning"/>
<property name="mfaProviderValidator" ref="mfaProviderValidator"/>
</bean>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public void setup() {

@After
public void cleanup() {
webDriver.get(zoneUrl + "/logout.do");
mfaZone.getConfig().getMfaConfig().setEnabled(false).setProviderId(null);
IntegrationTestUtils.createZoneOrUpdateSubdomain(adminClient, baseUrl, mfaZone.getId(), mfaZone.getSubdomain(), mfaZone.getConfig());
}
Expand All @@ -74,22 +75,10 @@ public void cleanup() {
public void testQRCodeScreen() throws Exception {

String zoneAdminToken = IntegrationTestUtils.getZoneAdminToken(baseUrl, serverRunning, mfaZone.getId());
ScimUser user = new ScimUser(null, new RandomValueStringGenerator(5).generate(), "first", "last");
user.setPrimaryEmail(user.getUserName());
user.setPassword(USER_PASSWORD);

user = IntegrationTestUtils.createUser(zoneAdminToken, baseUrl, user, mfaZone.getId());
MfaProvider provider = IntegrationTestUtils.createGoogleMfaProvider(baseUrl, zoneAdminToken, MockMvcUtils.constructGoogleMfaProvider(), mfaZone.getId());

mfaZone.getConfig().getMfaConfig().setEnabled(true).setProviderId(provider.getId());
mfaZone = IntegrationTestUtils.createZoneOrUpdateSubdomain(adminClient, baseUrl, "testzone1", mfaZone.getSubdomain() , mfaZone.getConfig());

webDriver.get(zoneUrl + "/logout.do");
webDriver.get(zoneUrl + "/login");
ScimUser user = createRandomUser(zoneAdminToken);
enableMfaInZone(zoneAdminToken);

webDriver.findElement(By.name("username")).sendKeys(user.getUserName());
webDriver.findElement(By.name("password")).sendKeys(USER_PASSWORD);
webDriver.findElement(By.xpath("//input[@value='Sign in']")).click();
performLogin(user);
assertEquals(zoneUrl + "/login/mfa/register", webDriver.getCurrentUrl());

assertThat(webDriver.findElement(By.id("qr")).getAttribute("src"), Matchers.containsString("chart.googleapis"));
Expand All @@ -106,4 +95,38 @@ public void checkAccessForTotpPage() {
assertEquals(zoneUrl + "/login", webDriver.getCurrentUrl());
}

@Test
public void testDisplayMfaIssuerOnRegisterPage() throws Exception{
String zoneAdminToken = IntegrationTestUtils.getZoneAdminToken(baseUrl, serverRunning, mfaZone.getId());
ScimUser user = createRandomUser(zoneAdminToken);
MfaProvider mfaProvider = enableMfaInZone(zoneAdminToken);

performLogin(user);

assertThat(webDriver.findElement(By.id("mfa-provider")).getText(), Matchers.containsString(mfaProvider.getName()));
}

private void performLogin(ScimUser user) {
webDriver.get(zoneUrl + "/login");

webDriver.findElement(By.name("username")).sendKeys(user.getUserName());
webDriver.findElement(By.name("password")).sendKeys(USER_PASSWORD);
webDriver.findElement(By.xpath("//input[@value='Sign in']")).click();
}

private MfaProvider enableMfaInZone(String zoneAdminToken) {
MfaProvider provider = IntegrationTestUtils.createGoogleMfaProvider(baseUrl, zoneAdminToken, MockMvcUtils.constructGoogleMfaProvider(), mfaZone.getId());
mfaZone.getConfig().getMfaConfig().setEnabled(true).setProviderId(provider.getId());
mfaZone = IntegrationTestUtils.createZoneOrUpdateSubdomain(adminClient, baseUrl, "testzone1", mfaZone.getSubdomain() , mfaZone.getConfig());
return provider;
}

private ScimUser createRandomUser(String zoneAdminToken) {
ScimUser user = new ScimUser(null, new RandomValueStringGenerator(5).generate(), "first", "last");
user.setPrimaryEmail(user.getUserName());
user.setPassword(USER_PASSWORD);

return IntegrationTestUtils.createUser(zoneAdminToken, baseUrl, user, mfaZone.getId());
}

}
Loading

0 comments on commit ff2384c

Please sign in to comment.