Landing page and user authorization for retrieving one fling

This commit is contained in:
Armin Friedl 2020-05-29 18:08:18 +02:00
parent f502402cb6
commit 4618cc9bff
Signed by: armin
GPG key ID: 48C726EEE7FBCBC8
9 changed files with 542 additions and 4 deletions

View file

@ -1,8 +1,12 @@
package net.friedl.fling.security; package net.friedl.fling.security;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import net.friedl.fling.security.authentication.FlingToken;
import net.friedl.fling.security.authentication.dto.UserAuthDto;
import net.friedl.fling.service.FlingService; import net.friedl.fling.service.FlingService;
@Service @Service
@ -20,4 +24,25 @@ public class AuthorizationService {
.orElseThrow() .orElseThrow()
.getAllowUpload(); .getAllowUpload();
} }
public boolean allowFlingAccess(UserAuthDto userAuth, String shareUrl) {
return userAuth.getShareId().equals(shareUrl);
}
public boolean allowFlingAccess(Long flingId) {
return false;
}
public boolean allowFlingAccess(FlingToken authentication, HttpServletRequest request) {
if(authentication.getGrantedFlingAuthority().getAuthority().equals(FlingAuthority.FLING_OWNER.name())) {
return true;
}
var shareId = request.getParameter("shareId");
var flingId = shareId != null
? flingService.findFlingByShareId(shareId).orElseThrow().getId()
: request.getParameter("flingId");
return authentication.getGrantedFlingAuthority().getFlingId().equals(flingId);
}
} }

View file

@ -53,17 +53,22 @@ public class FlingWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
.csrf().disable() .csrf().disable()
.cors(withDefaults()) .cors(withDefaults())
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
// Everybody can try to authenticate
.authorizeRequests() .authorizeRequests()
.antMatchers("/api/auth/**") .antMatchers("/api/auth/**")
.permitAll() .permitAll()
.and() .and()
// We need to go from most specific to more general.
// Hence, first define user permissions
.authorizeRequests() .authorizeRequests()
.antMatchers(HttpMethod.GET, "/api/fling/{flingId}/download") .antMatchers(HttpMethod.GET, "/api/fling/{flingId}/download")
.hasAuthority(FlingAuthority.FLING_USER.name()) .hasAuthority(FlingAuthority.FLING_USER.name())
.and() .and()
.authorizeRequests() .authorizeRequests()
.antMatchers("/api/**") .antMatchers(HttpMethod.POST, "/api/artifacts/{flingId}/**")
.hasAuthority(FlingAuthority.FLING_OWNER.name()) .access("hasAuthority('"+FlingAuthority.FLING_USER.name()+"') and @authorizationService.allowUpload(#flingId)")
.and() .and()
.authorizeRequests() .authorizeRequests()
// TODO: This is still insecure since URLs are not encrypted // TODO: This is still insecure since URLs are not encrypted
@ -71,8 +76,14 @@ public class FlingWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
.permitAll() .permitAll()
.and() .and()
.authorizeRequests() .authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/artifacts/{flingId}/**") .regexMatchers(HttpMethod.GET, "\\/api\\/fling\\?(shareId=|flingId=)[a-zA-Z0-9]+")
.access("hasAuthority('"+FlingAuthority.FLING_USER.name()+"') and @authorizationService.allowUpload(#flingId)"); .access("@authorizationService.allowFlingAccess(authentication, request)")
.and()
// And lastly, the owner is allowed everything
.authorizeRequests()
.antMatchers("/api/**")
.hasAuthority(FlingAuthority.FLING_OWNER.name());
//@formatter:on //@formatter:on
} }

View file

@ -7,9 +7,15 @@ import org.springframework.security.authentication.AbstractAuthenticationToken;
public class FlingToken extends AbstractAuthenticationToken { public class FlingToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = -1112423505610346583L; private static final long serialVersionUID = -1112423505610346583L;
private GrantedFlingAuthority grantedFlingAuthority;
public FlingToken(GrantedFlingAuthority authority) { public FlingToken(GrantedFlingAuthority authority) {
super(List.of(authority)); super(List.of(authority));
this.grantedFlingAuthority = authority;
}
public GrantedFlingAuthority getGrantedFlingAuthority() {
return this.grantedFlingAuthority;
} }
@Override @Override

View file

@ -10,16 +10,20 @@ import FlingAdmin from './components/admin/FlingAdmin';
import Unlock from './components/user/Unlock'; import Unlock from './components/user/Unlock';
import FlingUser from './components/user/FlingUser'; import FlingUser from './components/user/FlingUser';
import LandingPage from './components/LandingPage';
export default () => { export default () => {
return ( return (
<Switch> <Switch>
<Route exact path="/" component={LandingPage} />
<Route exact path="/admin/login" component={Login} /> <Route exact path="/admin/login" component={Login} />
<OwnerRoute exact path="/admin"><FlingAdmin /></OwnerRoute> <OwnerRoute exact path="/admin"><FlingAdmin /></OwnerRoute>
<OwnerRoute path="/admin/:fling"><FlingAdmin /></OwnerRoute> <OwnerRoute path="/admin/:fling"><FlingAdmin /></OwnerRoute>
<Route exact path="/unlock" component={Unlock} /> <Route exact path="/unlock" component={Unlock} />
<UserRoute exact path="/f/:shareId"><FlingUser /></UserRoute> <UserRoute exact path="/f/:shareId"><FlingUser /></UserRoute>
<Route match="*">Not implemented</Route> <Route match="*">Not implemented</Route>
</Switch> </Switch>
); );

View file

@ -0,0 +1,55 @@
import log from 'loglevel';
import React, {useState} from 'react';
import admin_area from './resources/admin_area.svg';
import view_fling from './resources/view_fling.svg';
export default function LandingPage() {
let [shareId, setShareId] = useState("");
function openAdminPage(ev) {
ev.preventDefault();
window.location = "/admin";
}
function openFling(ev) {
ev.preventDefault();
window.location = `/f/${shareId}`;
}
function changeShareId(ev) {
ev.preventDefault();
setShareId(ev.currentTarget.value);
}
return (
<div className="container-center">
<div id="landing-rows">
<div id="landing-header">
<h1>Welcome !</h1>
<h2>Where are you heading?</h2>
</div>
<div id="landing-content">
<div id="landing-tile">
<h5>I am the owner...</h5>
<img src={admin_area} alt="Admin area" />
<button className="btn btn-secondary input-group-btn btn-sm mt-2" onClick={openAdminPage}>Manage</button>
</div>
<div className="divider-vert" data-content="OR" />
<div id="landing-tile">
<h5>I got a code...</h5>
<img src={view_fling} alt="Fling view" />
<div className="input-group mt-2">
<input type="text" className="form-input input-sm" value={shareId} onChange={changeShareId} placeholder="My code" />
<button className="btn btn-secondary input-group-btn btn-sm" onClick={openFling}>Open</button>
</div>
</div>
</div>
</div>
</div>
);
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.3 KiB

View file

@ -0,0 +1,383 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="sending.svg"
xml:space="preserve"
viewBox="0 0 1042.2871 496.58731"
y="0px"
x="0px"
id="Layer_1"
version="1.1"
width="1042.2871"
height="496.58728"><metadata
id="metadata981"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs979"><inkscape:path-effect
scale_y_rel="false"
prop_scale="1"
strokepath="M 0,0 H 1"
endpoint_spacing_variation="0;1"
endpoint_edge_variation="0;1"
startpoint_spacing_variation="0;1"
startpoint_edge_variation="0;1"
count="5"
lpeversion="1"
is_visible="true"
id="path-effect1332"
effect="curvestitching" /><filter
inkscape:menu-tooltip="Deep and dark metal shading"
inkscape:menu="Non-Realistic 3D Shaders"
height="1.5"
width="1.5"
y="-0.25"
x="-0.25"
id="filter1372"
inkscape:label="Deep Metal"
style="color-interpolation-filters:sRGB"><feGaussianBlur
id="feGaussianBlur1370"
result="fbSourceGraphic"
stdDeviation="3.17893 0.738555" /><feColorMatrix
id="feColorMatrix1374"
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
in="fbSourceGraphic"
result="fbSourceGraphicAlpha" /><feGaussianBlur
in="fbSourceGraphic"
stdDeviation="2"
result="result12"
id="feGaussianBlur1376" /><feTurbulence
result="result1"
baseFrequency="0.03"
type="fractalNoise"
seed="0"
numOctaves="1"
id="feTurbulence1378" /><feDisplacementMap
result="result3"
xChannelSelector="R"
yChannelSelector="B"
scale="200"
in="result1"
id="feDisplacementMap1380"
in2="result12" /><feComposite
operator="in"
result="result14"
id="feComposite1382"
in2="result1" /><feGaussianBlur
result="result8"
stdDeviation="0.5"
in="result14"
id="feGaussianBlur1384" /><feConvolveMatrix
order="3 3"
kernelMatrix="1 1 1 1 -8 1 1 1 1 "
in="result8"
divisor="1"
targetX="1"
targetY="1"
preserveAlpha="true"
result="result0"
bias="0"
id="feConvolveMatrix1386" /><feColorMatrix
values="1"
in="result0"
result="result1"
type="luminanceToAlpha"
id="feColorMatrix1388" /><feComposite
k4="0"
k3="0"
k1="0"
result="result11"
operator="arithmetic"
k2="5"
in="result1"
id="feComposite1390"
in2="result1" /><feGaussianBlur
result="result7"
in="result11"
stdDeviation="0.2"
id="feGaussianBlur1392" /><feColorMatrix
result="result9"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 5 -0.5 "
id="feColorMatrix1394" /><feComposite
in="result12"
operator="in"
result="result13"
id="feComposite1396"
in2="result9" /><feFlood
flood-opacity="1"
result="result10"
flood-color="rgb(157,87,40)"
id="feFlood1398" /><feComposite
result="result15"
in="result10"
operator="in"
id="feComposite1400"
in2="result13" /><feComposite
result="fbSourceGraphic"
operator="in"
id="feComposite1402"
in2="fbSourceGraphic" /><feColorMatrix
id="feColorMatrix1404"
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
in="fbSourceGraphic"
result="fbSourceGraphicAlpha" /><feGaussianBlur
in="fbSourceGraphic"
stdDeviation="5"
result="result8"
id="feGaussianBlur1406" /><feComposite
operator="xor"
result="result19"
id="feComposite1408"
in2="result8" /><feComposite
k4="0"
k3="0"
k1="0"
k2="1"
operator="arithmetic"
result="result17"
id="feComposite1410"
in2="result8" /><feComposite
result="result6"
operator="xor"
id="feComposite1412"
in2="result17" /><feOffset
result="result18"
in="result6"
id="feOffset1414" /><feDisplacementMap
in="result18"
xChannelSelector="A"
yChannelSelector="A"
scale="100"
result="result4"
id="feDisplacementMap1416"
in2="result17" /><feComposite
k4="0"
k2="0"
k1="0"
in="result4"
result="result2"
operator="arithmetic"
k3="1"
id="feComposite1418"
in2="result4" /><feComposite
result="fbSourceGraphic"
in="result2"
operator="over"
id="feComposite1420"
in2="result2" /><feComposite
in="fbSourceGraphic"
operator="xor"
result="result15"
id="feComposite1422"
in2="fbSourceGraphic" /><feComposite
result="result16"
operator="in"
in="result15"
id="feComposite1424"
in2="result8" /></filter><filter
id="filter3291"
style="color-interpolation-filters:sRGB"
x="-0.2"
y="-0.2"
width="1.4"
height="1.4"
inkscape:menu-tooltip="Gel effect with strong refraction"
inkscape:menu="Ridges"
inkscape:label="Refractive Gel B"><feOffset
id="feOffset3267"
result="result3"
in="SourceAlpha"
dy="3"
dx="3" /><feGaussianBlur
id="feGaussianBlur3269"
result="result1"
in="result3"
stdDeviation="8" /><feComposite
id="feComposite3271"
result="result2"
in="SourceGraphic"
in2="result1"
operator="in" /><feComposite
id="feComposite3273"
in2="result2"
in="result2"
result="fbSourceGraphic"
operator="out" /><feColorMatrix
id="feColorMatrix3275"
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0 0 0 0 6 0 "
in="fbSourceGraphic"
result="fbSourceGraphicAlpha" /><feGaussianBlur
id="feGaussianBlur3277"
stdDeviation="3"
in="fbSourceGraphicAlpha"
result="result0" /><feSpecularLighting
id="feSpecularLighting3281"
in="result0"
result="result1"
lighting-color="#ffffff"
surfaceScale="5"
specularConstant="2"
specularExponent="20"><feDistantLight
id="feDistantLight3279"
elevation="35"
azimuth="235" /></feSpecularLighting><feComposite
id="feComposite3283"
in2="fbSourceGraphicAlpha"
in="result1"
result="result2"
operator="in" /><feComposite
k4="0"
k1="0"
id="feComposite3285"
result="result91"
in2="result2"
k3="3"
k2="1.5"
operator="arithmetic"
in="fbSourceGraphic" /><feBlend
id="feBlend3287"
in2="result91"
mode="screen" /><feConvolveMatrix
id="feConvolveMatrix3289"
divisor="3"
targetY="1"
targetX="1"
kernelMatrix="2 0 1 0 1 0 0 0 0 "
order="3 3" /></filter></defs><sodipodi:namedview
inkscape:current-layer="Layer_1"
inkscape:window-maximized="1"
inkscape:window-y="0"
inkscape:window-x="27"
inkscape:cy="347.45311"
inkscape:cx="596.97117"
inkscape:zoom="0.85058928"
showgrid="false"
id="namedview977"
inkscape:window-height="1052"
inkscape:window-width="1893"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff"
inkscape:document-rotation="0"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<path
id="path928"
d="M 1042.2871,0 686.9821,122.262 795.2101,143.849 1042.2851,0 Z"
style="fill:#4693d2;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path930"
d="m 686.9821,122.262 108.228,21.587 71.829,-41.819 z"
style="fill:#6babe0;fill-opacity:0.74902"
inkscape:connector-curvature="0" />
<path
id="path932"
d="M 795.2101,143.849 811.9751,271.427 1042.2851,0 Z"
style="fill:#0a62ad;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path934"
d="m 795.2101,143.849 16.765,127.578 102.937,-121.314 -17.769,-28.952 -35.202,29.386 5.1,-48.519 h -0.002 l -71.829,41.819 z"
style="fill:#277cc3;fill-opacity:0.85098"
inkscape:connector-curvature="0" />
<path
id="path936"
d="m 1042.2871,0 -208.21,173.809 -22.099,97.619 z"
style="fill:#fecd0d"
inkscape:connector-curvature="0" />
<path
id="path938"
d="m 861.9421,150.548 -27.865,23.261 -22.099,97.619 102.937,-121.314 -17.769,-28.952 -35.202,29.386 v -0.002 z"
style="fill:#6babe0;fill-opacity:0.74902"
inkscape:connector-curvature="0" />
<path
id="path940"
d="M 971.4601,242.264 1042.2871,0 l -208.21,173.809 137.385,68.455 z"
style="fill:#4693d2;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path942"
d="m 861.7851,150.548 -27.865,23.261 137.385,68.453 -74.314,-121.1 -35.207,29.388 v -0.002 z"
style="fill:#6babe0;fill-opacity:0.752941"
inkscape:connector-curvature="0" />
<g
id="g946"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g948"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g950"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g952"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g954"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g956"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g958"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g960"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g962"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g964"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g966"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g968"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g970"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g972"
transform="translate(616.95906,-144.17507)">
</g>
<g
id="g974"
transform="translate(616.95906,-144.17507)">
</g>
<path
sodipodi:nodetypes="cccscccccccccsccsccccccccccccc"
d="m 134.57328,354.18241 c 28.08128,-14.58672 60.20125,-8.11798 84.02882,11.48106 48.82406,32.03234 99.79822,83.35123 160.7581,90.69512 23.14647,2.47949 39.03138,4.88838 62.21367,3.28825 15.31463,-1.05707 45.41101,-4.19742 60.73437,-4.02011 34.43578,-2.68735 56.7121,-9.46951 86.77406,-28.38076 -12.35833,8.32998 22.7755,-12.15121 26.57753,-23.5598 18.18683,-28.11021 15.27972,-67.41362 -1.6973,-95.42532 -18.82569,-32.9823 -64.24591,-19.95233 -89.33298,-2.1831 -34.31038,19.8106 -20.54783,68.5908 1.3395,92.83086 35.77901,29.11795 88.63913,48.17663 134.2254,34.54023 21.69458,-5.06488 47.71825,-13.73135 65.64775,-27.08642 -6.25052,3.44455 14.7485,-11.15884 21.67399,-16.58277 10.19913,-6.12462 18.60002,-17.37833 25.04875,-27.3844 11.81453,-18.33181 18.79084,-38.23995 30.38365,-55.4868 9.24843,-9.34605 2.65313,-44.53697 -5.75041,-20.76609 -0.26827,10.28564 -2.99262,12.17953 -7.30655,21.22291 -8.50214,17.82321 -22.60115,41.46938 -32.19759,58.18806 -15.21945,17.60006 -45.23439,40.62701 -46.92804,40.50963 -5.58287,3.53015 -33.85902,16.92896 -50.05171,19.04801 -39.57228,10.24417 -81.67814,-2.20967 -114.43048,-25.15287 -24.01615,-16.57542 -37.14306,-49.76389 -29.25526,-77.99682 2.82719,-8.87473 15.0384,-19.47368 6.75089,-12.58871 24.20714,-16.28572 67.44474,-23.91905 81.83018,8.84439 15.96238,28.22468 15.32173,65.23484 -1.36049,92.96884 -8.42582,8.82239 -22.14275,18.55693 -14.70052,13.46849 -49.99539,21.6389 -103.26037,18.91824 -156.26249,24.14375 -35.05519,2.41939 -74.07831,-3.46518 -105.31623,-21.17729 -50.31666,-24.25531 -86.41417,-73.03448 -141.32919,-88.25916 -17.19754,5.46581 -36.96378,4.94609 -52.06742,14.82082 z"
style="fill:#4693d2;fill-opacity:1;stroke-width:0.755906;stroke-dasharray:0.755906, 1.51181;filter:url(#filter3291)"
id="path1428" /></svg>

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -250,3 +250,55 @@ tbody td {
.share-settings { .share-settings {
} }
/***************\
| LandingPage |
\***************/
#landing-rows {
display: flex;
flex-direction: column;
}
#landing-header {
text-align: center;
}
#landing-content {
display: flex;
flex-direction: row;
}
#landing-tile {
display: flex;
flex-direction: column;
margin-left: 2rem;
margin-right: 2rem;
margin-top: 1rem;
margin-bottom: 1rem;
}
#landing-tile h5 {
text-align: center;
}
#landing-tile img {
width: 10rem;
height: 8rem;
}
#landing-tile {
a {
text-decoration: none;
color: $primary-color;
&:visited {
text-decoration: none;
color: inherit;
}
}
input {
max-width: 7rem;
}
}