Spring Boot Security - konfiguracja z pliku

Spring Boot Security - konfiguracja z pliku
Jarek Korcek
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 4 lata
  • Postów:29
0

Backend napisany w mikroserwisach (spring boot cloud). W mikroserwisie Gateway który jest odpowiedzialny za api routing i sprawdzanie czy odpytujący ma odpowiednie uprawnienia mam obecnie zahardkodowana testową konfiguracje:

Kopiuj
@Override
	public void configure(WebSecurity webSecurity) {
		webSecurity.ignoring()
		.antMatchers("/user-service/customer/login/*")
		.antMatchers("/user-service/user/login");
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
		.antMatchers("/info").hasAuthority("ADMIN")
		//.antMatchers("/user-service/login").hasAuthority("ADMIN") 
		.antMatchers("/test3").hasRole("ADMIN")
		.and()
		.addFilter(new JwtFilter(authenticationManager()))
		.csrf().disable();
	}

W jaki sposób przenieść to do pliku? w jakiej lokalizacji taki plik powinien być?

S9
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 2 lata
  • Lokalizacja:Warszawa
  • Postów:1092
2

Chcesz przenieść cała konfigurację do application.properties?


Korges
  • Rejestracja:prawie 5 lat
  • Ostatnio:około 3 godziny
  • Postów:560
1

Do głowy mi przychodzi:

Kopiuj
@Value("${path.to.cośtam}")

Ale to i tak tylko przeniesienie stringów.
Możesz też zrobić różne klasy konfiguracyjne i nadać im adnotacje @profile tak żeby odpalało się to co chcesz.

edytowany 3x, ostatnio: Korges
Jarek Korcek
Też o tym pomyślałem, ale zastanawia mnie czy juz nie ma wbudowanego takiego mechanizmu zanim zastosuje swoje rozwiazanie
E9
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 10 godzin
  • Postów:216
1

Kiedyś robiłem coś takiego, w application.yml

Kopiuj
security:
  unprotectedEndpoints: /api/auth/**, /swagger-ui/**, /swagger-resources/**, /v2/api-docs

I w samym SecurityConfiguration

Kopiuj
    private final String[] unprotectedEndpoints;

    public SecurityConfiguration(@Value("${security.unprotectedEndpoints}") String unprotectedEndpoints) {
        this.unprotectedEndpoints = unprotectedEndpoints;
    }

    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers(unprotectedEndpoints);
    }

No ale z hasRole() nigdy nie widziałem takiej konfiguracji w pliku

edytowany 1x, ostatnio: Emdzej93
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:7 minut
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
4

Nic nie musisz robić. Już jest w pliku.


jeden i pół terabajta powinno wystarczyć każdemu
Zobacz pozostałe 4 komentarze
S9
No i? Security nie jest od tego żeby co 5 minut to zmieniać na prodzie.
danek
przecież aktualizacja konfgia i restart a przekompilować cala aplikacje i wrzucic nowa wersje to praktycznie to samo
E9
@danek: niby tak, ale w poprzedniej firmie miałem bardzo duży nacisk na to, by jak najwięcej rzeczy było wyniesione do konfiguracji w plikach których nie trzeba kompilować. Powodem był skopany proces CI/CD, który zabierał ponad godzinę, a w taki sposób nasz "lider techniczny" mógł wejść przez ssh, zmienić coś w pliku, zrestartować aplikację i gotowe. Strasznie się tylko później dziwił i denerwował, że skoro tego nie zacommitował, to po prostu następny deployment mu te konfigurację nadpisywał ;) Raz nawet uznał, że sabotujemy jego pracę, bo on coś ważnego akurat testował.
S9
@Emdzej93: to tylko świadczy o zje...nym środowisku pracy.
E9
@Aleksander32: w pełni się zgadzam, dlatego też jak nieco zmądrzałem to po prostu uciekłem do innego pracodawcy. Niemniej jednak, istnieją miejsca gdzie są takie wymagania i narzuca je architekt z 20 letnim stażem.
Jarek Korcek
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 4 lata
  • Postów:29
0

@Aleksander32: Tak do pliku .xml lub .properties.

Druga kwestia czy to dobra praktyka tego typu rzeczy miec w konfgiu

edytowany 2x, ostatnio: Jarek Korcek
S9
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 2 lata
  • Lokalizacja:Warszawa
  • Postów:1092
2

Nie jest, chyba że lubisz dreszcz emocji pt. "Ciekawe czy ktoś zhakuje API bo ktoś zapomniał endpointu w produkcyjnej konfiguracji"


edytowany 1x, ostatnio: scibi_92
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

Moim zdaniem źle do tego podchodzisz jeśli chcesz to zrobić TYLKO tutaj. Bo przecież to musi być spójne z kontrolerami i pewnie też z programmatic clientem w tym serwisie, więc wszystkie te wartości powinny pochodzić z jednego miejsca! Bo co ci da ze tutaj masz hardkodowanego stringa /api1 kiedy w kontrolerze ktoś zmieni na /api2 a w kliencie ktoś przypadkiem da /api3? Tylko że nie bardzo masz jak taką wartość wstrzyknąć z konfiga, szczególnie w przypadku tego klienta, który przecież może być wciagnięty jako zależność w zupełnie innym projekcie. W efekcie moim zdaniem jedyna dobra opcja to:

  1. Robisz public static String w kliencie, gdzie hardkodujesz te stringi odpowiedzialne za endpointy
  2. W kontrolerze importujesz sobie te stringi i definiujesz endpointy
  3. W security konfig importujesz te stringi i definiujesz security rules

Dzięki temu w kodzie każdy z tych stringów występuje tylko jeden raz.

Shameless plug ale:


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
ZN
  • Rejestracja:prawie 6 lat
  • Ostatnio:około 2 lata
  • Postów:49
0

Da się ale wtedy nie korzystasz z magii typu Spring security :) a implementujesz to co ci potrzebne sam

Jarek Korcek
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 4 lata
  • Postów:29
0

W takim razie czy w ogóle dobrym podejściem jest sprawdzanie autentykacji i autoryzacji na poziomie api gateway czy czasem nie lepiej ta logike przenieść do każdego z serwisów i wtedy każdy z nich sprawdzałby uprawnienia tylko dla swoich endpointow? Chciałem uniknąć walidacji na każdym z serwisów poniżej gateway'a i wtedy api gateway by odrzucał już na wstępie te odpytania które nie maja tokena czy tez uprawnień do odpytywanego endpointa. (wyciagajac adresy do jakeis klasy statycznej jak podsunął pomysł Shalom byłby w tym wypadku dobrym pomysłem)

edytowany 2x, ostatnio: Jarek Korcek
Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:2 dni
  • Postów:1874
2

Nawet jak to będzie wyciągnięte do jakiejś klasy jako static, musisz w jakiś sposób zapewnić, że zmiany zostaną wszędzie zaciągnięte w postaci wdrożenia z nową wersją biblioteki. Więc IMHO to o czym pisze Shalom albo można zapewnić zrzucając odpowiedzialność za rejestrację route na zespół opiekujący się danym serwisem, albo jakiś mechanizm automatycznej aktualizacji routy w api-gateway.

Odnośnie sprawdzania uprawnień, skalowalnym podejściem jest autoryzacja na poziomie określonej domeny, której dotyczą te uprawnienia. Inaczej w api-gateway zrobi się śmietnik.


”Engineering is easy. People are hard.” Bill Coughran
Szymek
  • Rejestracja:ponad 22 lata
  • Ostatnio:ponad 2 lata
1

Moim zdaniem dobrą praktyką jest kontrola uprawnień jak najbliżej kodu wykonującego opreację lub danych (przydaje się w dużych projektach). Jeżeli będziesz sprawdzać uprawnienia na poziomie api gateway, to zawsze ktoś się może wstrzelić z boku. Często też wersje samych serwisów mogą sie rozjechać i nagle API jest dostępne dla wszystkich po niefortunnym wdrożeniu.

Jeśli chodzi o sprawdzanie uprawnień użytkownika to polecam użyć @EnableGlobalMethodSecurity(prePostEnabled=true) i pisać kod tak:

Kopiuj
@Controller
public UserManagementController {

  @RequestMapping(method = RequestMethod.GET)
  @PreAuthorize("hasAuthority('CAN_LIST_USERS')")
  public List<RestUser> listUsers() {
    // ...
  }

  @RequestMapping(method = RequestMethod.POST)
  @PreAuthorize("hasAuthority('CAN_SUSPEND_USER')")
  public void suspendUser(@RequestParam UUID userId) {
    // ...
  }

}

Dodatkowo polecam używać ról jako kontenerów na uprawnienia (authorities). I w samym kodzie sprawdzać authorities. Przykładowo:

  • ROLE_USER_MANAGEMENT zawiera
  • CAN_LIST_USERS
  • CAN_SUSPEND_USER
  • CAN_CHANGE_USER_ROLES
  • etc.

Dzięki temu zyskujesz elastyczność. Jeżeli trzeba dodać nową rolę to nie trzeba przerabiać wszystkich aplikacji, tylko definiujesz nową rolę i przypisane do niej uprawnienia.

edytowany 1x, ostatnio: Szymek
Shalom
oh tak, stringly typing, a potem literówka w takim stringu i nagle security znika
Szymek
Możesz rozwinąć swój komentarz? Jak zrobisz typo w adnotacji, to się do endpointa nie dostaniesz. Dodatkowo to można bardzo prosto (a nawet trzeba!) przetestować.
Shalom
Żeby daleko nie szukać, a dzisiaj: https://4programmers.net/Forum/Java/347876-spring_boot_security_unautorized_401_konfiguracja_nie_dziala?p=1736088#id1736088 :D podobny problem, wynikający z pisania stringów w kodzie i opierania się na nich.
Szymek
Nie widzę związku z moim przykładem. Typo w parametrze adnotacji spowoduje, że endpoint przestanie być dostępny. Napisanie testu automatycznego weryfikujące poprawność adnotacji jest bardzo proste - chyba nie muszę nikogo przekonywać, że warto takie rzeczy testować. Chcę od razu zaznaczyć, że nie jestem fanem SpELa. Coś bardziej skomplikowanego niż to co jest moim przykładzie (rozbudowane wyrażenia logiczne) stanowczo odradzam.
Shalom
Ale to jest dokładnie taki sam problem -> masz kod który zależy od stringa w kodzie. Tam też błąd w stringu powodował ze coś nie działało (401). Sęk w tym, że lepiej kiedy o błędach mówi kompilator, a nie test, szczególnie że tutaj potrzebujesz test integracyjny który to wszystko odpali, a jest nadal wielu wyznawców mocków, którzy takiego testu nigdy nie napiszą. No i znów taki sam problem jak w podanym przeze mnie wątku -> autor zauważył że coś nie działa ale nie był w stanie stwierdzić co.
Szymek
Zgadzam się, że najlepiej kiedy kompilator mówi o błędzie, ale niestety rola lub uprawnienie muszą gdzieś wystąpić jako String. Typo zawsze może się tam wkrać. Zasadnicza różnica jest tylko taka, że String zaproponowany przeze mnie jest dłuższy - tak dwukrotnie - w dalszym ciagu można do stałych wyciągnąć jeżeli te nazwy się bardzo często powtarzają (głownie role, bo w przypadku uprawnień - nie powinny). Jeśli chodzi o test, to kontroler i tak trzeba integracyjnym testem przejechać, żeby uprawnić się, że wszystko pomapowane poprawnie.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)