Skip to content
Permalink
Browse files
retrofitted drawer unlock
  • Loading branch information
mgeiss committed Jun 14, 2017
1 parent 2d7e458 commit 7ca53ac6aa05d837dd43a2bd7382017f01436906
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 70 deletions.
@@ -19,7 +19,7 @@
import io.mifos.core.api.annotation.ThrowsExceptions;
import io.mifos.core.api.util.CustomFeignClientsConfiguration;
import io.mifos.teller.api.v1.domain.Teller;
import io.mifos.teller.api.v1.domain.TellerAuthentication;
import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
import io.mifos.teller.api.v1.domain.TellerBalanceSheet;
import io.mifos.teller.api.v1.domain.TellerManagementCommand;
import io.mifos.teller.api.v1.domain.TellerTransaction;
@@ -118,7 +118,7 @@ TellerBalanceSheet getBalance(@PathVariable("officeIdentifier") final String off
@PathVariable("tellerCode") final String tellerCode);

@RequestMapping(
value = "/teller/{tellerCode}/auth",
value = "/teller/{tellerCode}/drawer",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
@@ -128,8 +128,8 @@ TellerBalanceSheet getBalance(@PathVariable("officeIdentifier") final String off
@ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerNotFoundException.class),
@ThrowsException(status = HttpStatus.CONFLICT, exception = TellerNotFoundException.class)
})
String auth(@PathVariable("tellerCode") final String tellerCode,
@RequestBody @Valid final TellerAuthentication tellerAuthentication);
void unlockDrawer(@PathVariable("tellerCode") final String tellerCode,
@RequestBody @Valid final UnlockDrawerCommand unlockDrawerCommand);

@RequestMapping(
value = "/teller/{tellerCode}",
@@ -15,12 +15,12 @@
*/
package io.mifos.teller.api.v1.domain;

public class TellerAuthentication {
public class UnlockDrawerCommand {

private String employeeIdentifier;
private String password;

public TellerAuthentication() {
public UnlockDrawerCommand() {
super();
}

@@ -20,7 +20,7 @@
import io.mifos.teller.api.v1.client.TellerNotFoundException;
import io.mifos.teller.api.v1.client.TellerValidationException;
import io.mifos.teller.api.v1.domain.Teller;
import io.mifos.teller.api.v1.domain.TellerAuthentication;
import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
import io.mifos.teller.api.v1.domain.TellerManagementCommand;
import io.mifos.teller.api.v1.domain.TellerTransaction;
import io.mifos.teller.util.TellerGenerator;
@@ -44,47 +44,45 @@ public TestTellerOperation() {
public void shouldAuthenticate() throws Exception {
final Teller teller = this.prepareTeller();

final TellerAuthentication tellerAuthentication = new TellerAuthentication();
tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
tellerAuthentication.setPassword(teller.getPassword());
final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
unlockDrawerCommand.setPassword(teller.getPassword());

final String auth = super.testSubject.auth(teller.getCode(), tellerAuthentication);

Assert.assertEquals(auth, teller.getCode());
super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
}


@Test(expected = TellerNotFoundException.class)
public void shouldNotAuthenticateUserMismatch() throws Exception {
final Teller teller = this.prepareTeller();

final TellerAuthentication tellerAuthentication = new TellerAuthentication();
tellerAuthentication.setEmployeeIdentifier("unassigneduser");
tellerAuthentication.setPassword(teller.getPassword());
final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
unlockDrawerCommand.setEmployeeIdentifier("unassigneduser");
unlockDrawerCommand.setPassword(teller.getPassword());

super.testSubject.auth(teller.getCode(), tellerAuthentication);
super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
}

@Test(expected = TellerNotFoundException.class)
public void shouldNotAuthenticatePasswordMismatch() throws Exception {
final Teller teller = this.prepareTeller();

final TellerAuthentication tellerAuthentication = new TellerAuthentication();
tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
tellerAuthentication.setPassword("wrongpasword");
final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
unlockDrawerCommand.setPassword("wrongpasword");

super.testSubject.auth(teller.getCode(), tellerAuthentication);
super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
}

@Test
public void shouldPauseTeller() throws Exception {
final Teller teller = this.prepareTeller();

final TellerAuthentication tellerAuthentication = new TellerAuthentication();
tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
tellerAuthentication.setPassword(teller.getPassword());
final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
unlockDrawerCommand.setPassword(teller.getPassword());

super.testSubject.auth(teller.getCode(), tellerAuthentication);
super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);

super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());

@@ -104,11 +102,11 @@ public void shouldNotPauseTellerNotAuthenticated() throws Exception {
public void shouldOpenAccount() throws Exception {
final Teller teller = this.prepareTeller();

final TellerAuthentication tellerAuthentication = new TellerAuthentication();
tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
tellerAuthentication.setPassword(teller.getPassword());
final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
unlockDrawerCommand.setPassword(teller.getPassword());

super.testSubject.auth(teller.getCode(), tellerAuthentication);
super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);

super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());

@@ -135,11 +133,11 @@ public void shouldOpenAccount() throws Exception {
public void shouldCloseAccount() throws Exception {
final Teller teller = this.prepareTeller();

final TellerAuthentication tellerAuthentication = new TellerAuthentication();
tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
tellerAuthentication.setPassword(teller.getPassword());
final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
unlockDrawerCommand.setPassword(teller.getPassword());

super.testSubject.auth(teller.getCode(), tellerAuthentication);
super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);

super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());

@@ -166,11 +164,11 @@ public void shouldCloseAccount() throws Exception {
public void shouldTransferAccountToAccount() throws Exception {
final Teller teller = this.prepareTeller();

final TellerAuthentication tellerAuthentication = new TellerAuthentication();
tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
tellerAuthentication.setPassword(teller.getPassword());
final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
unlockDrawerCommand.setPassword(teller.getPassword());

super.testSubject.auth(teller.getCode(), tellerAuthentication);
super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);

super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());

@@ -200,11 +198,11 @@ public void shouldTransferAccountToAccount() throws Exception {
public void shouldDeposit() throws Exception {
final Teller teller = this.prepareTeller();

final TellerAuthentication tellerAuthentication = new TellerAuthentication();
tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
tellerAuthentication.setPassword(teller.getPassword());
final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
unlockDrawerCommand.setPassword(teller.getPassword());

super.testSubject.auth(teller.getCode(), tellerAuthentication);
super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);

super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());

@@ -231,11 +229,11 @@ public void shouldDeposit() throws Exception {
public void shouldWithdraw() throws Exception {
final Teller teller = this.prepareTeller();

final TellerAuthentication tellerAuthentication = new TellerAuthentication();
tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
tellerAuthentication.setPassword(teller.getPassword());
final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
unlockDrawerCommand.setPassword(teller.getPassword());

super.testSubject.auth(teller.getCode(), tellerAuthentication);
super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);

super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());

@@ -15,23 +15,23 @@
*/
package io.mifos.teller.service.internal.command;

import io.mifos.teller.api.v1.domain.TellerAuthentication;
import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;

public class AuthenticateTellerCommand {
public class DrawerUnlockCommand {
private final String tellerCode;
private final TellerAuthentication tellerAuthentication;
private final UnlockDrawerCommand unlockDrawerCommand;

public AuthenticateTellerCommand(final String tellerCode, final TellerAuthentication tellerAuthentication) {
public DrawerUnlockCommand(final String tellerCode, final UnlockDrawerCommand unlockDrawerCommand) {
super();
this.tellerCode = tellerCode;
this.tellerAuthentication = tellerAuthentication;
this.unlockDrawerCommand = unlockDrawerCommand;
}

public String tellerCode() {
return this.tellerCode;
}

public TellerAuthentication tellerAuthentication() {
return this.tellerAuthentication;
public UnlockDrawerCommand tellerAuthentication() {
return this.unlockDrawerCommand;
}
}
@@ -28,9 +28,9 @@
import io.mifos.teller.ServiceConstants;
import io.mifos.teller.api.v1.EventConstants;
import io.mifos.teller.api.v1.domain.Teller;
import io.mifos.teller.api.v1.domain.TellerAuthentication;
import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
import io.mifos.teller.api.v1.domain.TellerManagementCommand;
import io.mifos.teller.service.internal.command.AuthenticateTellerCommand;
import io.mifos.teller.service.internal.command.DrawerUnlockCommand;
import io.mifos.teller.service.internal.command.ChangeTellerCommand;
import io.mifos.teller.service.internal.command.CloseTellerCommand;
import io.mifos.teller.service.internal.command.CreateTellerCommand;
@@ -208,23 +208,22 @@ public String process(final CloseTellerCommand closeTellerCommand) {
@Transactional
@CommandHandler
@EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.AUTHENTICATE_TELLER)
public String process(final AuthenticateTellerCommand authenticateTellerCommand) {
final String tellerCode = authenticateTellerCommand.tellerCode();
final TellerAuthentication tellerAuthentication = authenticateTellerCommand.tellerAuthentication();
public String process(final DrawerUnlockCommand drawerUnlockCommand) {
final String tellerCode = drawerUnlockCommand.tellerCode();
final UnlockDrawerCommand unlockDrawerCommand = drawerUnlockCommand.tellerAuthentication();

final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
if (optionalTeller.isPresent()) {
final TellerEntity tellerEntity = optionalTeller.get();
if (!tellerEntity.getState().equals(Teller.State.OPEN.name())
&& !tellerEntity.getState().equals(Teller.State.PAUSED.name())) {
if (tellerEntity.getState().equals(Teller.State.CLOSED.name())) {
throw ServiceException.notFound("Teller {0} not found.", tellerCode);
}

if (!UserContextHolder.checkedGetUser().equals(tellerEntity.getAssignedEmployeeIdentifier())) {
throw ServiceException.notFound("Teller {0} not found.", tellerCode);
}

final byte[] givenPassword = this.hashGenerator.hash(tellerAuthentication.getPassword(),
final byte[] givenPassword = this.hashGenerator.hash(unlockDrawerCommand.getPassword(),
Base64Utils.decodeFromString(tellerEntity.getSalt()), ServiceConstants.ITERATION_COUNT, ServiceConstants.LENGTH);

if (!tellerEntity.getPassword().equals(Base64Utils.encodeToString(givenPassword))) {
@@ -23,10 +23,10 @@
import io.mifos.teller.ServiceConstants;
import io.mifos.teller.api.v1.PermittableGroupIds;
import io.mifos.teller.api.v1.domain.Teller;
import io.mifos.teller.api.v1.domain.TellerAuthentication;
import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
import io.mifos.teller.api.v1.domain.TellerTransaction;
import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
import io.mifos.teller.service.internal.command.AuthenticateTellerCommand;
import io.mifos.teller.service.internal.command.DrawerUnlockCommand;
import io.mifos.teller.service.internal.command.CancelTellerTransactionCommand;
import io.mifos.teller.service.internal.command.ConfirmTellerTransactionCommand;
import io.mifos.teller.service.internal.command.InitializeTellerTransactionCommand;
@@ -76,26 +76,29 @@ public TellerOperationRestController(@Qualifier(ServiceConstants.LOGGER_NAME) fi

@Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_OPERATION)
@RequestMapping(
value = "/auth",
value = "/drawer",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
@ResponseBody
ResponseEntity<String> auth(@PathVariable("tellerCode") final String tellerCode,
@RequestBody @Valid final TellerAuthentication tellerAuthentication) {
ResponseEntity<Void> unlockDrawer(@PathVariable("tellerCode") final String tellerCode,
@RequestBody @Valid final UnlockDrawerCommand unlockDrawerCommand) {
final Teller teller = this.verifyTeller(tellerCode);

if (!teller.getAssignedEmployee().equals(tellerAuthentication.getEmployeeIdentifier())) {
throw ServiceException.badRequest("User {0} is not assigned to teller.", tellerAuthentication.getEmployeeIdentifier());
if (!teller.getAssignedEmployee().equals(unlockDrawerCommand.getEmployeeIdentifier())) {
throw ServiceException.badRequest("User {0} is not assigned to teller.", unlockDrawerCommand.getEmployeeIdentifier());
}

this.verifyEmployee(teller);

try {
return ResponseEntity.ok(
this.commandGateway.process(new AuthenticateTellerCommand(tellerCode, tellerAuthentication), String.class).get()
);
final String unlockedTeller =
this.commandGateway.process(new DrawerUnlockCommand(tellerCode, unlockDrawerCommand), String.class).get();

this.logger.debug("Drawer {0} unlocked", unlockedTeller);

return ResponseEntity.ok().build();
} catch (final Exception e) {
throw ServiceException.notFound("Teller {0} not found.", teller.getCode());
}
@@ -0,0 +1,55 @@
<!--
Copyright 2017 The Mifos Initiative.
Licensed 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.
-->
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/teller.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/archive/teller.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>7</maxHistory>
<totalSizeCap>2GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<logger name="com" level="WARN">
<appender-ref ref="STDOUT" />
</logger>

<logger name="org" level="WARN">
<appender-ref ref="STDOUT" />
</logger>

<logger name="io" level="WARN">
<appender-ref ref="STDOUT" />
</logger>

<logger name="net" level="WARN">
<appender-ref ref="STDOUT" />
</logger>

<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</configuration>

0 comments on commit 7ca53ac

Please sign in to comment.