Spring MVC binding to same #RequestMapping - spring

Suppose we have this code for login & we want if the credential was for admin page the RequestMapping be for admin & if it was for user credential the user redirect to user panel.
now, the main page of both oppose the same url as I defined in my code below, something like :
http://localhost:8080/project/{username}/main
my question is :
how we can separate these two method in here when they have the same RequestMapping "main" after the login checking finished inside the Controller class?
#RequestMapping(value = "/login")
public String welcome(#RequestParam("j_username") String username, #RequestParam("j_password") String password, HttpSession session, Model model) throws RemoteException, NotBoundException {
int checkAccount = uiClient.checkAdminAccount(username, password);
if (checkAccount == 1) {
session.setAttribute("username", username);
return "redirect:/" + username + "/main";
} else if (checkAccount == 0) {
checkAccount = uiClient.checkAccount(username, password);
if (checkAccount == 1) {
session.setAttribute("username", username);
return "redirect:/" + username + "/main";
} else if (checkAccount == 0) {
return "login";
}
} else {
return "databaseError";
}
return "login";
}
#RequestMapping(value = "/{username}/main")
public String indexPage(#PathVariable("username") String username) {
return "/user/userPanel";
}
#RequestMapping(value = "{username}/main")
public String adminIndexPage(#PathVariable("username") String username){
return "/admin/adminPanel";
}
I mean, is there any way like special tag or something that we can put for each Mapping & separate them after the login process finished so the admin redirect to adminPanel & the user also redirect to userPanel but both with the same url:
http://localhost:8080/project/{username}/main
???

What about this way:
#RequestMapping(value = "/login")
public String welcome(#RequestParam("j_username") String username, #RequestParam("j_password") String password, HttpSession session, Model model) throws RemoteException, NotBoundException {
int checkAccount = uiClient.checkAdminAccount(username, password);
if (checkAccount == 1) {
session.setAttribute("username", username);
session.setAttribute("userrole", "Admin");
return "redirect:/" + username + "/main";
} else if (checkAccount == 0) {
checkAccount = uiClient.checkAccount(username, password);
if (checkAccount == 1) {
session.setAttribute("username", username);
session.setAttribute("userrole", "Admin");
return "redirect:/" + username + "/main";
} else if (checkAccount == 0) {
return "login";
}
} else {
return "databaseError";
}
return "login";
}
#RequestMapping(value = "/{username}/main")
public String indexPage(#PathVariable("username") String username) {
if ("Admin".equals(session.getAttribute("userrole"))) {
return "/admin/adminPanel";
} else {
return "/user/userPanel";
}
}
For simplicity, I didn't use Spring Security to check user role here.

Related

.Net Framework API Controller won't recognize Route attributes

I have created an API Controller using .Net Framework as follows:
public class ApplicationUsersController : ApiController
{
[Route("api/ApplicationUser/{username}/{password}")]
[ResponseType(typeof(ApplicationUser))]
public IHttpActionResult GetApplicationUser(string username, string password)
{
ApplicationUser user = new ApplicationUser()
//Code to populate user.
return Ok(user);
}
[Route("api/ApplicationUser/{username}")]
[ResponseType(typeof(ApplicationUser))]
public IHttpActionResult GetApplicationUser(string username)
{
ApplicationUser user = new ApplicationUser()
//Code to populate user.
return Ok(user);
}
// PUT: api/ApplicationUsers/5
[Route("api/ApplicationUser/{username}")]
[ResponseType(typeof(void))]
public IHttpActionResult PutApplicationUser(string username, ApplicationUser ApplicationUser)
{
//Code to update user
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/ApplicationUsers
[Route("api/ApplicationUser")]
[ResponseType(typeof(ApplicationUser))]
public IHttpActionResult PostApplicationUser(ApplicationUser ApplicationUser)
{
//Code to create new user
return Ok(ApplicationUser);
// return CreatedAtRoute("api/ApplicationUser/{username}", new { username = ApplicationUser.UserName }, ApplicationUser);
}
// DELETE: api/ApplicationUsers/5
[Route("api/ApplicationUser/{username}")]
[ResponseType(typeof(ApplicationUser))]
public IHttpActionResult DeleteApplicationUser(string username)
{
//Code to populate user then delete the record.
return Ok(user);
}
}
When I make a Get call to api/ApplicationUser/{username}/{password}, it works fine. If I make a Post call to api/ApplicationUser, it works fine. If I make a Get, Put or Delete call to api/ApplicationUser/{username}, I get a "not found" error. Is there something else I need to do to make it recognize the route?
Thanks,
Jim
**** Update ****
I have discovered that it will recognize the route as long as the username doesn't end with .something such as .com. The thing is, I am using email addresses as the username. Is there a rule somewhere that a REST url can't end with .somthing? Is there a way around this?
The problem was the format of the parameters. Apparently a url can't end with a .com or other domain suffix. What I did was to convert the parameters to Base64. I created these two extension functions.
public static string ToBase64(this string value)
{
try
{
byte[] bytes = Encoding.UTF8.GetBytes(value);
return Convert.ToBase64String(bytes);
}
catch (Exception)
{
return value;
}
}
public static string FromBase64(this string value)
{
try
{
byte[] bytes = Convert.FromBase64String(value);
return Encoding.UTF8.GetString(bytes);
}
catch(Exception)
{
return value;
}
}
In the controller, I did something like:
[Route("api/ApplicationUser/{username}")]
[ResponseType(typeof(ApplicationUser))]
public IHttpActionResult GetApplicationUser(string username)
{
username = username.FromBase64();
ApplicationUser user = new ApplicationUser()
//Code to populate user.
return Ok(user);
}
In the client, I did something like:
async Task<ApplicationUser> IApplicationUserService.GetApplicationUser(string username)
{
username = username.ToBase64();
ApplicationUser ret = null;
var response = await _httpClient.GetAsync($"api/ApplicationUser/{username}");
if (response.IsSuccessStatusCode)
{
ret = await JsonSerializer.DeserializeAsync<ApplicationUser>
(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
}
return ret; ;
}
Cheers,
Jim

How to send a HTTP response in Zuul PRE_TYPE Filter

I want to prevent not logged user form accessing the proxy. I can throw an exception but the response is 404 instead of `401 or '403'. It it possible?
Filter code:
#Component
public class CustomZuulFilter extends ZuulFilter {
//FIXME - if 401,403 get the new token??, fallbackMethod = "fall",
#HystrixCommand(
commandProperties = {
#HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000"),
#HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")
}
)
#Override
public Object run() {
logger.debug("Adding zulu header");
String userName = getLoggedUser();
RequestContext ctx = RequestContext.getCurrentContext();
if (userName == null) {
// throw new RuntimeException("User not authenticated");
logger.info("User not authenticated");
ctx.setResponseStatusCode(401);
ctx.sendZuulResponse();
return null;
}
return null;
}
private String getLoggedUser() {
[...]
}
#Override
public boolean shouldFilter() {
return true;
}
#Override
public String filterType() {
return PRE_TYPE;
}
#Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 1;
}
}
It might be a bit late, but i think you can remove ctx.sendZuulResponse();
and add ctx.setSendZuulResponse(false);

How to write into session with web api?

I am writing an authentication code. I am authenticating against the web server. currently my code take the username and password from xcode and send it over to the web service via the URL which then returns a json string that I am reading in xcode. When the connection is succefull I want to create a session and in xcode i want to read that session.
Web Api:
public class SessionController : ApiController
{
public bool loggedin = false;
public class MyHttpControllerHandler: HttpControllerHandler, IRequiresSessionState
{
public MyHttpControllerHandler(RouteData routeData): base(routeData)
{ }
}
public class MyHttpControllerRouteHandler : HttpControllerRouteHandler
{
protected override IHttpHandler GetHttpHandler(
RequestContext requestContext)
{
return new MyHttpControllerHandler(requestContext.RouteData);
}
}
public void Authenticate(string txtLoginId, string txtPassword)
{
Subs objSub = SubService.GetSubs(txtLoginId.Trim(), txtPassword.Trim());
if (objSub != null)
{
loggedin = true;
}
else
loggedin = false;
}
public string Get(string user, string pass)
{
byte[] data = Convert.FromBase64String(pass);
string password = Encoding.UTF8.GetString(data);
Authenticate(user, password);
if(loggedin == true)
{
var session = HttpContext.Current.Session;
session["Time"] = DateTime.Now;
return "Session Time: " + session["Time"] + user;
}else
return "Session is not availabe " + user;
}
}
it returns the following error on this line,
session["Time"] = DateTime.Now;
ExceptionMessage":"Object reference not set to an instance of an object."

EasyMock to test exceptions

I am trying to test with EasyMock the service layer by mocking the DAO.
One of the methods in my DAO class is shown below.
public BrickStreamUserVO getUserDetails(String userName, String password)
{
BrickStreamUserVO usrObj = null;
try
{
String sqlStr = "SELECT * FROM USER_T WHERE USER_NAME LIKE '" + userName + "'
AND PASSWORD = '" + password + "'";
usrObj = getJdbcTemplate().queryForObject(sqlStr, new BrickStreamUserMapper());
logger.info("Getting user details....");
if(usrObj==null)
throw new UserException("Invalid Login parameters");
}
catch (Exception e)
{
logger.error(e);
throw new UserException("Invalid Login parameters");
}
return usrObj;
}
And here is my test code
public class BrickStreamServiceImplTest
{
private BrickStreamServiceImpl serviceImpl;
#Before
public void buildService()
{
serviceImpl = new BrickStreamServiceImpl();
}
#Test
public void testGetUserDetails()
{
BrickStreamDaoImpl daoImplMock = createMock(BrickStreamDaoImpl.class);
expect(daoImplMock.getUserDetails("user", "pwd")).
andReturn(new BrickStreamUserVO());
replay(daoImplMock);
serviceImpl.setBrickStreamDao(daoImplMock);
serviceImpl.getUserDetails("user", "pwd");
verify(daoImplMock);
}
}
How can I test the method to throw the UserException, you can see that if the usrObj object is null it throws a UserException.
If you mock the getUserDetails method, you won't be able to test its behavior.
You may want to extract a method where you do the user query, and mock it.
public BrickStreamUserVO queryForUser(String userName, String password) {
String sqlStr = "SELECT * FROM USER_T WHERE USER_NAME LIKE '" + userName + "'
AND PASSWORD = '" + password + "'";
return getJdbcTemplate().queryForObject(sqlStr, new BrickStreamUserMapper());
}
public BrickStreamUserVO getUserDetails(String userName, String password)
{
BrickStreamUserVO usrObj = null;
try
{
usrObj = queryForUser(userName, password);
logger.info("Getting user details....");
if(usrObj==null) {
throw new UserException("Invalid Login parameters");
}
} catch (Exception e) {
logger.error(e);
throw new UserException("Invalid Login parameters");
}
return usrObj;
}
In your test class :
#Test(expected = UserException.class)
public void testGetUserDetails()
{
BrickStreamDaoImpl daoImplMock = createMockBuilder(BrickStreamDaoImpl.class).addMockedMethod("queryForUser").createMock();
expect(daoImplMock.queryForUser("user", "pwd")).andReturn(null);
replay(daoImplMock);
serviceImpl.setBrickStreamDao(daoImplMock);
serviceImpl.getUserDetails("user", "pwd");
}

Shiro always redirects me to login.jsp

Here is the config from shiro.ini
shiro.loginUrl = /login.jsp
######### URL CONFIG ################### [urls] /login.jsp = anon /public/login/** = anon /public/app/** = authc
Stripes...
#UrlBinding("/public/app/")
public class CalculatorActionBean implements ActionBean {
.....
}
#UrlBinding("/public/login/")
public class UserAuthenticateBean implements ActionBean {
private static final transient Logger log = LoggerFactory.getLogger(UserAuthenticateBean.class);
private ActionBeanContext context;
private String username;
private String password;
private String message;
public ActionBeanContext getContext() {
return context;
}
public void setContext(ActionBeanContext context) {
this.context = context;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#DefaultHandler
#DontValidate
public Resolution defaultHander() {
return new ForwardResolution("/login.jsp");
}
public Resolution login() {
Subject currentUser = SecurityUtils.getSubject();
log.info("CU=" + currentUser.toString());
if (!currentUser.isAuthenticated()) {
TenantAuthenticationToken token = new TenantAuthenticationToken(username, password, "jdbcRealm");
//UsernamePasswordToken token = new UsernamePasswordToken("akumar", "ash");
token.setRememberMe(true);
try {
currentUser.login(token);
} catch (UnknownAccountException uae) {
log.info("There is no user with username of " + token.getPrincipal());
} catch (IncorrectCredentialsException ice) {
log.info("Password for account " + token.getPrincipal() + " was incorrect!");
} catch (LockedAccountException lae) {
log.info("The account for username " + token.getPrincipal() + " is locked. "
+ "Please contact your administrator to unlock it.");
} // ... catch more exceptions here (maybe custom ones specific to your application?
catch (AuthenticationException ae) {
//unexpected condition? error?
ae.printStackTrace();
}
}
if (currentUser.isAuthenticated()) {
message = "Success";
} else {
message = "Fail";
}
System.out.println(message);
message += getUsername() + getPassword();
return new ForwardResolution("/logged_in.jsp");
}
}
logged_in.jsp
app
Now if I remove the line
/public/app/** = authc
from shiro.ini, I can access /public/app for a logged in user and guest
If I keep the line, then noone can access the page and it goes back to login.jsp
Driving me nuts!
help!!
Change your urls config to have 'authc' filter the actual login url:
[main]
...
authc.loginUrl = /login.jsp
[urls]
/login.jsp = authc
/public/login/** = anon
/public/app/** = authc
The authc filter is smart enough to know if a request is not authenticated to still let it go through to the underlying page so a user can log in.

Resources