I am trying to fix a bug in a web application using java 8, spring boot, Spring MVC and front end with angular cli. When the user logins the application and is created a menu considering the user profile permission with java, but the application uses angular router with static paths, so if the user rewrite the URL he can access anything even without permissions.
const routes: Routes = [
{
path: '',
component: WebservicesComponent,
children: [
{ path: 'perfis', loadChildren: './wsperfis/wsperfis.module#WsperfisModule', },
{ path: 'acessos', loadChildren: './wsacessos/wsacessos.module#WsacessosModule', },
{ path: 'novoAcesso', loadChildren: './novo-acesso/novo-acesso.module#NovoAcessoModule', },
{ path: 'servicos', loadChildren: './wsservicos/wsservicos.module#WsservicosModule' },
{ path: 'novoperfil', loadChildren: './wsnovoperfil/wsnovoperfil.module#WsnovoperfilModule' }
]
}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class WebservicesRoutingModule {
}
#CrossOrigin
#RequestMapping("/menu")
public List<Object> menu(#RequestParam(value = "idPerfil") int idPerfil) {
List<Menu> menus = menuService.getMenus(idPerfil);
List<Object> menu = new ArrayList<Object>();
Map<String, Object> mapMenu = new HashMap<String, Object>();
Map<String, String> mapSubMenu = new HashMap<String, String>();
List<Object> listMapSubMenu = new ArrayList<Object>();
for (Menu menuItem : menus) {
if (!mapMenu.containsValue(menuItem.getPaiPrompt())) {
mapMenu = new HashMap<String, Object>();
listMapSubMenu = new ArrayList<Object>();
mapMenu.put(LABEL, menuItem.getPaiPrompt());
mapMenu.put(URL, menuItem.getPaiUrl());
mapMenu.put(ICON, menuItem.getPaiIcon());
for (Menu submenu : menus) {
if (menuItem.getPaiPrompt().equals(submenu.getPaiPrompt())) {
mapSubMenu = new HashMap<String, String>();
mapSubMenu.put(LABEL, submenu.getFilhoPrompt());
mapSubMenu.put(URL, submenu.getFilhoUrl());
mapSubMenu.put(ICON, submenu.getFilhoIcon());
listMapSubMenu.add(mapSubMenu);
}
}
mapMenu.put(ITEMS, listMapSubMenu);
menu.add(mapMenu);
}
}
return menu;
}
You should add a validation on your front and backend, for example, when path changes in frontend and component is mounted it checks for session sending its path id, backend compare that versus asigned menu, all this before making any other api call.
Another solution more complex (and secure) is adding the validation on api itself, by checking menus or user profiles, this way even if user access a page he should not (its mapped in js), he won't access unauthorized apis.
I could do it using a canActiveChild validation in a Guard file, but now I am if a issue in the first time that I call it.
The service that a call there stay with the status pending in the the first time that I call it, but in the next calls it works fine.
Fallow the code:
constructor(private router: Router, private _cookieService: CookieService, private comumService: ComumService) {}
canActivate() {
if (this._cookieService.get('AuthorizationToken')) {
return true;
}
this.router.navigate(['login']);
return false;
}
canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
console.log('state.url: ' + state.url);
// tslint:disable-next-line:triple-equals
if (state.url == '/dashboard' || this.validaAcesso(state.url)) {
return true;
} else {
console.log('Entrou aqui!!!');
window.alert('You don\'t have permission to view this page');
this.router.navigate(['dashboard']);
return false;
}
}
validaAcesso(url: string) {
this._cookieService.getAll();
this.comumService.validaAcesso(url).subscribe((data: Boolean) => {
console.log(data.valueOf());
if (data.valueOf()) {
console.log('validaAcesso return true');
this.result = true;
} else {
console.log('validaAcesso return false');
this.result = false;
}
});
return this.result;
}
}
Related
I'm trying to implement parallel execution of autotests using JUnit 5 and GEB. At the moment, the tests are already running in parallel. The problem is that every page element must be visible at the time the page object is created. If the object was not displayed on the page, then when you try to access it, a new browser object is created with a new page, starting an extra thread. How can this be avoided?
package tests
import geb.Browserimport geb.Pageimport geb.junit5.GebReportingTest
import org.junit.jupiter.api.AfterEachimport org.junit.jupiter.api.BeforeEachimport org.junit.jupiter.api.Testimport org.junit.jupiter.api.extension.ExtendWithimport io.github.bonigarcia.seljup.SeleniumJupiterimport org.openqa.selenium.chrome.ChromeDriver;import pages.CbsLoginPageimport static org.assertj.core.api.Assertions.*
#ExtendWith(SeleniumJupiter.class)class LoginToCbsTest extends GebReportingTest {public Browser browserpublic CbsLoginPage page
#BeforeEach
public void classLevelSetup() {
browser = new Browser()
browser.setDriver(new ChromeDriver())
page = browser.createPage(CbsLoginPage.class)
}
#AfterEach
public void teardown() {
browser.quit()
}
#Test
void loginFailsWhenPasswordIsWrong() {
// When
page.fillCredentialsForm("username", "123_Wrong_password")
page.clickLoginButton()
// Then
verifyLoginErrorIsDisplayed()
}
#Test
void loginFailsWhenUsernameIsWrong() {
// When
page.fillCredentialsForm("Wrong_username", "password")
page.clickLoginButton()
// Then
verifyLoginErrorIsDisplayed()
}
package pages
import geb.Pageimport modules.CbsLoginPageModule
import static geb.Browser.drive
class CbsLoginPage extends Page {static at = { title == "Log in to Application" }
static content = {
loginForm { module(CbsLoginPageModule) }
}
void fillCredentialsForm(String username, String password) {
drive(getBrowser(), {
getBrowser().to(this)
loginForm.loginField.value(username)
loginForm.passwordField.value(password)
})
}
void clickLoginButton() {
drive(getBrowser(), {
getBrowser().at(this)
loginForm.loginButton.click()
})
}
void getErrorMessage() {
drive(getBrowser(), {
getBrowser().at(this)
page
waitFor { $("div", innerHTML: contains("Invalid username or password.")) //This element is not visible when page was created}
})
}
}
package modules
import geb.Module
class CbsLoginPageModule extends Module {
static content = {form { $("form") }
loginField { form.$(id: "name") }
passwordField { form.$(id: "password") }
loginButton { form.$(name: "login") }
}
}
/*This is the Geb configuration file.
See: http://www.gebish.org/manual/current/#configuration
*/
import org.openqa.selenium.chrome.ChromeDriver
waiting {timeout = 2}
environments {
driver = { new ChromeDriver() }
}reportsDir = new File("target/runtime_reports_dir")baseUrl = "url"
plugins {id "idea"id "groovy"}
repositories {mavenCentral()}
dependencies {testImplementation 'io.github.bonigarcia:selenium-jupiter:4.0.1'testImplementation 'org.seleniumhq.selenium:selenium-java:4.1.2'testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.1'testImplementation 'org.gebish:geb-junit5:5.1'testImplementation 'org.assertj:assertj-core:3.22.0'}
task chromedriverTest(type: Test) {useJUnitPlatform()}
task chromeheadlessTest(type: Test) {useJUnitPlatform()}
test {useJUnitPlatform()testLogging {events "passed", "skipped", "failed"}
systemProperty("junit.jupiter.execution.parallel.enabled" , "true")
systemProperty("junit.jupiter.execution.parallel.config.strategy", "fixed")
systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent")
systemProperty("junit.jupiter.execution.parallel.config.fixed.parallelism", 2)
}
I'm trying to create a connection between 2 existing entities PropertyGroup and CustomFieldSet. Use-case is irrelevant.
So I created an EntityExtension:
public function extendFields(FieldCollection $collection): void
{
$collection->add(
(new ManyToOneAssociationField('customFieldSet', 'custom_field_set', CustomFieldSetDefinition::class))
);
}
public function getDefinitionClass(): string
{
return PropertyGroupDefinition::class;
}
And override the administration component to also include this association when loading the entity:
Component.override('sw-property-detail', {
methods: {
loadEntityData() {
this.isLoading = true;
const criteria = this.defaultCriteria;
criteria.addAssociation('customFieldSet', new Criteria(1, 500));
this.propertyRepository.get(this.groupId, Shopware.Context.api, criteria)
.then((currentGroup) => {
this.propertyGroup = currentGroup;
this.isLoading = false;
}).catch(() => {
this.isLoading = false;
});
}
}
});
(I tried to override defaultCriteria but that didn't work because of this.$super being unable to access computed properties).
But it keeps saying FRAMEWORK__ASSOCIATION_NOT_FOUND. I debugged the EntityDefinition and it seems that this extension is not even loaded.
I checked if my EntityExtension is loaded in the Symfony container and it is, but it seems that it doesn't reach the entity definition.
The EntityExtension seems to be missing the addition of a FkField inside the function extendFields:
public function extendFields(FieldCollection $collection): void
{
$collection->add(
(new FkField('custom_field_set', 'customFieldSetId', CustomFieldSetDefinition::class)),
);
$collection->add(
(new ManyToOneAssociationField('customFieldSet', 'custom_field_set', CustomFieldSetDefinition::class))
);
}
A new use statement has to be added for the FkField:
use Shopware\Core\Framework\DataAbstractionLayer\Field\FkField;
I have created one demo in mvc 5 and now I need to create one custom filter in my demo. I have used mvc 5.
I need to check every time what method is execute like is a ajax call or action method call in mvc.
Here I have write like this code in my class.
public class UserSession
: System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var session = filterContext.HttpContext.Session;
if (ApplicationSession.IsSessionAlive)
return;
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var ajaxRedirectTarget = new RouteValueDictionary { { "action", "FailAuthenticationAjax" }, { "controller", "Home" } };
filterContext.Result = new RedirectToRouteResult(ajaxRedirectTarget);
}
else
{
var redirectTarget = new RouteValueDictionary { { "action", "Login" }, { "controller", "Account" } };
filterContext.Result = new RedirectToRouteResult(redirectTarget);
}
}
}
but I got error like this UserSession.OnActionExecuting(ActionExecutingContext): no suitable method found to override
After I have put this class on my controller like this.
[UserSession]
public class DashboardController
{
}
any one know how to fixed this issue in mvc 5?
How do I configure ServiceStack to serve specific error pages (404, 500, etc.) depending on the type of error being returned?
Currently, I'm using the RawHttpHandler below code to ensure that a request for a HTML file is authenticated. However, if the user specifies a non-existent file or endpoint, how can I have it return my 404.html page.
this.RawHttpHandlers.Add(httpReq =>
{
var session = httpReq.GetSession();
if(!session.IsAuthenticated) {
var isHtmlFileRequest = httpReq.PathInfo.EndsWith(".html");
if(isHtmlFileRequest && !files.Any(s => httpReq.PathInfo.ToLower().Contains(s))) {
return new RedirectHttpHandler {
AbsoluteUrl = "/Login.html"
};
}
}
return null;
});
The Error Handling wiki shows different ways to Customize Handling of Exceptions in ServiceStack, e.g you can redirect 404 errors to /404.cshtml with:
public override void Configure(Container container)
{
this.CustomHttpHandlers[HttpStatusCode.NotFound] =
new RazorHandler("/404");
}
CustomHttpHandlers can be any IServiceStackHandler which is just a HttpHandler that supports both ASP.NET and HttpListener requests. The easiest way to create one is to just inherit from IServiceStackHandler. Here's an example of a Custom Static File Handler similar to StaticFileHandler except it only writes the specified filePath instead of using the HTTP Request path:
public class CustomStaticFileHandler : HttpAsyncTaskHandler
{
string filePath;
public CustomStaticFileHandler(string filePath)
{
this.filePath = filePath;
}
public override void ProcessRequest(HttpContextBase context)
{
var httpReq = context.ToRequest(GetType().GetOperationName());
ProcessRequest(httpReq, httpReq.Response, httpReq.OperationName);
}
public override void ProcessRequest(IRequest request, IResponse response,
string operationName)
{
response.EndHttpHandlerRequest(skipClose: true, afterHeaders: r =>
{
var file = HostContext.VirtualPathProvider.GetFile(filePath);
if (file == null)
throw new HttpException(404, "Not Found");
r.SetContentLength(file.Length);
var outputStream = r.OutputStream;
using (var fs = file.OpenRead())
{
fs.CopyTo(outputStream, BufferSize);
outputStream.Flush();
}
}
}
}
This can then be registered as normal, i.e:
public override void Configure(Container container)
{
this.CustomHttpHandlers[HttpStatusCode.NotFound] =
new CustomStaticFileHandler("/404.html");
}
I am working on an application where I would like a url like so User\1\Class\Create would map to the Class controller and the Create action, but when I apply it, it doesn't pick it up.
Below is how I have the route registered (it is at the top of the list):
routes.MapRoute(
name: "UserClass",
url: "User/{userId}/Class/Create",
defaults: new { controller = "Class", action = "Create", userId= "" },
constraints: new { userId= #"\d+" }
);
(I have also tried it by omitting the userId="" default)
This is paired with this code:
public class ClassController : BaseController
{
public ActionResult Create(int userId)
{
var vm = new ClassEditorViewModel
{
Class = new Class { UserId = userId },
ClassEnrollmentStatuses = new SelectList(Db.ClassEnrollmentStatuses.ToList(), "Id", "Name")
};
return View(vm);
}
}
But this doesn't work. When I use Route Debugger (by Phil Haack) it doesn't use the above route and selects the {*catchall} route.
What am I doing wrong with the route configuration to make it not be used?
Deleted the route and re-typing it resolved the issue.