- 엔터프라이즈 블록체인
- 안드로이드 웹뷰
- 스칼라 동시성
- play 강좌
- 파이썬 동시성
- Play2 로 웹 개발
- 파이썬 강좌
- 파이썬 머신러닝
- Adapter 패턴
- 스칼라 강좌
- akka 강좌
- Hyperledger fabric gossip protocol
- 파이썬 데이터분석
- 하이퍼레저 패브릭
- hyperledger fabric
- play2 강좌
인증토큰을 이용한 Restful 스프링 보안 (번역) 본문
인증토큰을 이용한 Restful 스프링 보안 (번역)[하마] 이승현 (firstname.lastname@example.org) 2015. 6. 2. 16:22
역주: 이 포스트를 읽기전에 스프링 보안 폼기반 기본인증에 대해 읽어본후에 보면 이해하는데 도움이 될것이다.
Spring Security: 커스텀 토큰 기반 스프링 REST인증
RESTful Spring Security with Authentication Token
JULY 27, 2014 24 COMMENTS
HTTP authentication and tokens
Big question is what mechanism of authentication we want to use. If for nothing else, than at least for username (login) and password we will have SSL/TLS in place, so let’s say we will have HTTPS there all the time. This blurs the difference between classical HTTP Basic and Digest access authentication. So I decided to support Basic only for simplicity. For even easier development I introduced custom X-Username and X-Password headers, which allowed to test my solution with curl and similar tools entering plain values.
I’ve read more than a couple of articles and while I hardly became an expert on security, authentication (with HTTP or not), REST or tokens, I felt I got the basics. I also got familiar with enough ideas that I had to do some choices. I thought it would be easier, but obviously there are many ways how to construct a token. And people are probably still inventing more. So I decided to use randomly generated token that does not utilize user’s password at all – but it doesn’t really matter. You somehow create that token, that’s it. I aimed for solution that allows me to change this behavior easily.
Spring Security for REST?
Book Spring Security 3.1 by Robert Winch and Peter Mularien was another important source of understanding what is happening here. I tackled Spring Security before but never had a chance to go in-depth (that is beyond reactive Google/StackOverflow and some reference documentation reading), mostly because I tried to get in-depth with something else. Now was the time to understand what this framework is about. Good book, nice examples – maybe some UML class diagrams would help when introducing new important classes and interfaces and their roles.
The result is my take on RESTful Spring Security – it’s not really that revolutionary, but I tried to do couple of things differently. I even provided UML diagram. So I’ll copy it from README.md right here, ok?
Now what is going on here and – if you insist – how is this different from philipsorst’s solution?
- I wasn’t interested in real UI, so I tested it with any REST testing extension you can find, or with curl. In the end I even put together mini-framework based on bash and curl.
- I wasn’t interested in JPA/DB. I wanted as little frameworks thrown in as possible. So there is DAO with hardcoded users.
- I also wanted to come up with design that clearly separates the concept (package restsec) from any concrete implementation (secimpl), principles from details, Spring Security from the domain/application code (domain/mvc). Looking at the class diagram I think I did quite well.
- I wanted to try access control configured in XML and using annotations like @PreAuthenticate.
- Then there are some side-quests – I practiced some Gradle in combination with Spring Boot as my Bill Of Materials (kinda Maven style import scope) and I tested WildFly 8.1 (not really important).
- Finally – I wanted to document it sufficiently, both in code (comments) and in README + planned this post too. For self documentation. It pays off. I don’t remember what I need to do to make client certificates up and running on Tomcat, but I know where to look at (if it is not obsolete yet). And I used my own articles here and there already! (Actually, even my colleagues googled out my articles and found them helpful – you can’t imagine how it made me proud. ;-))
Spring Security going session-less
So how is it all working together? Because everything related to HTTP and authentication is concentrated essentially in TokenAuthenticationFilter, you don’t need any unprotected login URL. Filter is sitting in Spring Security filter chain, specifically in FORM_LOGIN_FILTER position. All you need is to provide authentication headers in any request. Because we are RESTful, we don’t want to utilize session at all. If you check spring-security.xml, this is set in http element:
It is important to set it to stateless (don’t use session at all), not to never (which allows Spring Security to use if it somehow exists already, just don’t create it).
Let’s stop at this statelessness for a while, shall we? This does not mean that there is no server-side state at all. It just means that we don’t work with HTTP session. We still need to remember valid tokens – we may do so within DB, application context, shared distributed memory, wherever – that is definitely stateful. But from HTTP standpoint, we should be RESTful enough now. Also we utilize Spring’s SecurityContextHolder because it makes sense if you want to benefit from other Spring Security stuff, like their annotations, etc. This way we smuggle our security information using a thread-local variable (default behavior) during each single request.
Before we get to business, let us see how anonymous access works first. For that assume that these are our first request and we didn’t authenticate before. In the following sequence diagrams, grey stuff is from Spring, rest is ours.
As any other model, this one is not complete or exact. Our filter is part of Spring Security chain and definitely is not called directly by browser. But in any case it’s the first moment we are interested in. Virtually every request goes through this filter (unless it avoids part of the application secured Spring Security completely). If we are accessing something available for unauthenticated user, we get what we want.
Second scenario tries to access something protected. This will not get to our Spring MVC controller:
It actually gets all the way to its proxy (in our case CGLib based, because our Controller does not implement any interface) and there an implementation of AccessDecisionManager finds out that anonymous user can’t access the method and AccessDeniedException is thrown. This is caught by ExceptionTranslationFilter (part of Spring Security chain) which calls authentication entry point for this kind of exception. Normal applications use the entry point it to redirect to a login screen. We don’t want to do that, but we need to implement it, so it sets the HTTP response status (401).
It’s very easy to debug it all and it’s very nice to browse through Spring code. Maybe Spring got big and complex (well it does a lot of things now), but their code is on the positive side of quality spectrum – understandable and well documented.
Login, login! Login this lap!
(Sorry, F1 race today, you know.) Four things may be happening in our application. You may be anonymous, you may be authenticated already, you’re logging in, or logging out. My implementation tries not to mix things together much, you should do just one of these things in a single request. Let’s log in to get authenticated. Login request can continue to the REST resource and return data, but I chose otherwise. This can be reimplemented of course –TokenAuthenticationFilter#checkLogin would call doNotContinueWithRequestProcessing only if the response is not 200. But currently it works this way. Here is the diagram:
If our filter finds information that looks like login (and it must be POST), it will pass username/password toAuthenticationService. This is still our part of solution and glues the filter with the rest of Spring Security. It calls Springs AuthenticationManager, which in turns calls our implementation of UserDetailsService, which provides username and password (in our case plain, not a good solution of course). Not to plague the diagram with stuff, I skipped Spring’s PasswordEncoder which helps authentication manager to decide if we can go on. If we can, we get back to our security service, which populates Spring’s SecurityContextHolder and now is the time to get the token.
For this we have separate component – TokenManager – which creates and stores the token for the user. Currently only one token per user is supported, but you can implement your own approach here. Actually if you reimplementAuthenticationService considerably, there may be nothing to call TokenManager. There’s a lot of freedom here, but I think TokenManager is the place where most of the customization can go into. How to create the tokens? How to store them? How to check them? Or expire them? However you want to answer these questions, TokenManager is your guy. You still may need to adjust authentication service or filter – for instance to add some HTTP related information (IP address?) into token.
Long story short? If everything is alright, HTTP response returns status 200 and the header X-Auth-Token contains the token next requests should use to prove who you are.
Here we don’t care what HTTP method is used. After login, this should be easy to understand:
You already know all the players, here we just first check whether provided token is indeed one of those we know – and if so, we populate SecurityContextHolder. In case of 401, we don’t even bother calling the rest of the chain. The rest (cases 200 and 403) is in Spring’s hands.
Hence we can rush towards…
Logout should invalidate user’s sess… ehm, token, obviously. That implies valid token is provided. We also insist on POST and require specific URL. We could also request logout with another HTTP header, or with “logout” mentioned in X-Auth-Token, etc. Here it is:
And that’s it really!
You could see all the important players on the diagrams, some of them are our classes, some of them are part of Spring Security “auto-magic”. I’m sure even XML configuration is much clearer now. There is great deal of freedom here – you may bypass Spring Security authentication manager altogether, for instance – don’t know why, but there may be reasons.
I’m not done yet. Later we’ll need to integrate this with some reliable Windows Domain SSO authentication (so far we count on Waffle), not to mention with the rest of the application.
That “demo app” is a mix of XML configuration and annotations, so check those out, check the comments, README, etc. I really tried different things just to find out how it all works (like that mandatory ROLE_ prefix!) and I’m still probably just skimming the surface. But still better than two weeks ago.
And that concludes my post and my first campaign in this war.
'Spring' 카테고리의 다른 글
|Angular JS and Spring Security 1 ~4 편 (번역) (0)||2015.07.11|
|Mybatis-spring 버전별 의존성 요구사항 (0)||2015.07.10|
|component-scan / annotation-config / annotation-driven 차이점 (2)||2015.07.09|
|Spring for android - 예제 소스 분석 (2) (0)||2015.07.03|
|Spring for android - 예제 실행해보기 (1) (1)||2015.07.03|
|인증토큰을 이용한 Restful 스프링 보안 (번역) (1)||2015.06.02|
2021.08.12 18:06 신고
제2의 비트코인 꼭보세요!! (이제 올라갈듯 ㅋ)
2008년에 비트코인을 매일 50코인을 무료로 채굴할 수 있었습니다. 대부분의 사람들은 가치가 없다고 느꼈습니다. 지금 비트코인(Bitcoin)은 1코인당 6000만원 상당의 가치가 있습니다.
2011년에 라이트코인이 선보였고, 매일 100코인을 무료로 채굴할 수 있었습니다. 대부분의 사람들은 이것이 여전히 가치가 없다고 생각했습니다. 라이트코인(Lite coin)은 현재 1코인에 30만원입니다.
이더리움이 2015년에 나왔습니다. 매일 30코인을 무료로 채굴할 수 있었습니다. 대부분의 사람들은 여전히 그것을 믿지 않았습니다. 이제 이더이움(Ethereum)은 1코인당 300만원 상당의 가치가 있습니다.
현재 전 세계적으로 돌풍을 일으키고 있는 상장을 준비중인 최고의 가치를 내재하고 있는 코인을 알려드립니다.
파이코인은 2019년에 태어났고 몇 번의 반감기를 거쳐 지금 하루에 6코인정도를 무료로 채굴할 수 있습니다.
다음 반감기 오기전 혹은 무료채굴 종료 전에 서두르셔야 합니다.
비트코인의 단점을 보완하여 스마트폰으로 채굴 할수 있는 파이코인.
스마트폰의 성능에 전혀 지장이 없으며, 하루 1번의 스위칭으로 24시간(1세션)동안 무료 채굴 합니다.
이 황금같은 기회를 놓치지 마세요..!!
파이(PI)는 스탠퍼드 박사들이 개발한 새로운 디지털 화폐이며 전 세계적으로 2100만 명 이상의 사용자가 존재합니다.
파이를 받으시려면 앱스토어에 파이네트워크(pi network) 검색 설치 후 가입 시 저의 사용자 이름 firenews 누르시면 가입됩니다.
파이코인 이외에 2번째로 관심있는 코인인 비(bee)코인은 현재 1200만명이 넘고 올해 상장합니다.
앱스토어에서 bee network 치고 다운로드받아 추천인 firenews1004 입니다.
영국에서 나온 올해 9월 상장예정인 유망한 이글코인은 앱스토어에서 이글코인 치시고 다운받으셔서 추천인 firenews 입니다.
싱가폴에서 나온 올해 상장예정인 전망 높은 ANT코인은 앱스토어에서 ANT NETWORK 치시고 다운 받아 추천인 firenews1004 입니다.
카카오그룹에서 나온 유망한 코인인 카우카우코인은 핫빗코리아에 상장했으며 아직 채굴 가능합니다.
카우카우코인 다운 받으셔서 추천인 ZBKJNQ 입니다.